|HowTo] Add a webapp as a sideload of /e/ self-hosted cloud


I managed to install a full brand new self-hosted /e/ Cloud, from scratch.
It’s working fine, so my next step was to add some webapps I like on the same VPS hosting.
As /e/ cloud is a full ecosystem based on Docker, I wanted to somehow integrate some Docker-based webapps into it.

As a exercise, I installed Zenphoto (https://www.zenphoto.org/).

Fortunately /e/ devs have provided a guide in /mnt/repo-base/docs/add_vhost.md , thanks @thilo :slight_smile:

First of all, I created a CNAME DNS record (better to do it first, because of propagation delays …) :

zenphoto 86400 IN CNAME mail.domain.tld (<-NEW)
mail 86400 IN A xx.xx.xx.xx

Next, as I’m lazy, I searched for a ready-made Docker image, found https://hub.docker.com/r/bender77/zenphoto.
Ok, Zenphoto is not at the latest version in this image, but it has some interesting benefits for my needs :

  • it uses an external database (good for me, I will be able to integrate into /e/ Cloud Mariadb)
  • it is well documented, has a GitLab link, …

But it’s gonna take a little preparation …

First, prepare the Docker Compose environment using the YAML file provided with /e/ Cloud.
So I added the following lines to /mnt/repo-base/docker-compose.yml (1) :

     image: bender77/zenphoto:latest
     container_name: zenphoto
     restart: unless-stopped
       - serverbase
       - /mnt/repo-base/volumes/zenphoto/www:/var/www/html
       - /mnt/repo-base/config-dynamic/letsencrypt/certstore:/certs:ro
       - mariadb

If I had set restart as “always”, I could add to the existing nginx “depends_on” section :

       - zenphoto

Next is to add an nginx site, it’s easily done by creating the file /mnt/repo-base/config-dynamic/nginx/sites-enabled/zenphoto.conf (2) :

server {
  listen 8000;
  server_name zenphoto.domain.tld;
  location / {
    return 301 https://$host$request_uri;

server {
  listen 4430 ssl http2;
  server_name zenphoto.domain.tld;

  ssl_certificate /certs/live/zenphoto.domain.tld/fullchain.pem;
  ssl_certificate_key /certs/live/zenphoto.domain.tld/privkey.pem;

  include /etc/nginx/params/ssl_params;
  include /etc/nginx/params/headers_params;

  client_max_body_size 4096M;

  location / {
    proxy_pass https://zenphoto:443;
    include /etc/nginx/params/proxy_params;

I could have restarted nginx at this step, but I didn’t … Why ?
Because, as stated in the site configuration file, I’ll have to generate a new Let’s Encrypt certificate … and that can only be done with nginx off ! (3)

Next, the tricky part with Mariadb database … Maybe there is another easier way to deal with this thing, anyway here is how I managed to get it working (honestly, Oracle or DB2 are more friendly to me) :flushed:

  • first, get the Mariadb container ID and shell to it : docker exec -it mariadb bash
  • then mysql -u root -p (using MYSQL_ROOT_PASSWORD from /mnt/repo-base/.env)
  • in mysql shell, entered (4) :

use mysql;
create or replace user ‘zenphoto’@‘172.18.0.%’ identified by ‘somekindofsillypassword’;
grant all privileges on \aenphoto.* to ‘zenphoto’@‘172.18.0.%’ identified by ‘thesamesillypassword’ with grant option;
create database zenphoto;

Pffffu ! Job done :sweat:

Ok, now the easy part : docker pull bender77/zenphoto.

Next (last but not least), the certificate.
As stated before, I’ll have to shut down nginx (docker stop nginx).
Certificate generation is made quite simple with the script provided by /e/ devs :smiley:
Just added my domain to /mnt/repo-base/config-dynamic/letsencrypt/autorenew/ssl-domains.dat, launched /mnt/repo-base/scripts/ssl-renew.sh, et voilà !
Checked everything’s ok by listing /mnt/repo-base/config-dynamic/letsencrypt/certstore/live/zenphoto.domain.tld/ content.

Then, I could start all : docker-compose up -d.

And do some magics inside zenphoto container to have apache2 handle https (I won’t go further with this, well-documented).

Finally, reward myself with a good beer :beer:
Cheers !


(1) see https://docs.docker.com/compose/compose-file/
First line is Compose service name
Next is image name, with version tag
Restart is not “always” as this app is not mandatory
The network is already defined by /e/ Cloud, I’m just re-using it
The www volume mapping is suggested by the Docker image author, adapted to /e/ Cloud storage tree
The certs volume mapping is to activate https inside ZenPhoto, it’s the only way to have it work fine
And finally some dependencies, this is what we need
NO network port exposition, as I will use the /e/ Cloud nginx engine :wink:

(2) see http://nginx.org/en/docs/
This file is quite similar to those provided by /e/ Cloud, some tips :

  • ports 8000 & 4430 are nginx listening ports, remapped by Docker (try docker-compose ps from /mnt/repo-base/)
  • the zenphoto hostname is provided by the integrated Docker DNS (the IP address is provided by Docker as well)
  • I added the client_max_body_size to permit photo uploads :wink:
  • I activated https inside ZenPhoto’s Docker container, so proxy is to https/443 not http/80 (proxy_pass directive)

(3) see https://certbot.eff.org/docs/install.html#system-requirements
As the script we use is creating certificate in standalone mode, certbot launches a pseudo-http server on port 80, which conflicts with our nginx :frowning:

(4) see https://mariadb.com/kb/en/account-management-sql-commands/
Also, is the internal Docker network (allowing containers to communicate)

Regain your privacy! Adopt /e/ the unGoogled mobile OS and online servicesphone