For a long time I wanted a good solution for sharing files with friends and family. I found Owncloud to suite my needs. Luckily there was already a docker image for this that would make my life easier. I just wanted to do some customization like:
- I wanted to add letsencrypt to the web-server, so I can get https for encrypted communication.
- I wanted to move it to a custom port, because I don’t want shodan and other malware to easily find my Owncloud server
- I wanted to separate data and configuration for easy upgrade of owncloud.
So here are my steps to get everything running under Docker.
Dockerfile
First I made a directory for the docker project “opt/docker/owncloud”. Then I create a file named “Dockerfile”:
1 FROM owncloud 2 3 WORKDIR "/root" 4 5 RUN apt-get update && \ 6 apt-get install -y wget smbclient vim mysql-client 7 8 RUN wget https://dl.eff.org/certbot-auto && \ 9 chmod a+x certbot-auto && \ 10 ./certbot-auto -n ; echo Done 11 12 COPY startup.sh /startup.sh 13 COPY backup-owncloud.sh /backup-owncloud.sh 14 15 RUN ln -s /etc/apache2/mods-available/ssl.load /etc/apache2/mods-enabled/ssl.load && \ 16 ln -s /etc/apache2/sites-available/default-ssl.conf /etc/apache2/sites-enabled/default-ssl.conf 17 18 CMD ["/startup.sh"]
This file tells Docker to:
- Line 1: Build it on top of the official image called “owncloud”.
- Line 5-10: Install the programs I want in addition to the original image. I want to be able to do SMB mounts, and I want to do letsencrypt certificates.
- Line 12-13: I copy two custom scripts to my Owncloud image. I have made a special startup-script and a script for doing backups. These will be shown later in this blog posting.
- Line 15-16: Here I tell apache to enable the SSL module and also to enable SSL on the default website.
- Line 18: Tells docker to run the startup.sh-script when a new container is instantiated from my image.
Startup Script
Then I created the “startup.sh” script (and chmod it 755):
1 #!/bin/bash 2 3 ./certbot-auto certonly --standalone -d ${domainname} --agree-tos --non-interactive --manual-public-ip-logging-ok --email ${letsencrypt_email} 4 5 sed -i "s/SSLCertificateFile.*/SSLCertificateFile \/etc\/letsencrypt\/live\/${domainname}\/fullchain.pem/" /etc/apache2/sites-enabled/default-ssl.conf 6 sed -i "s/SSLCertificateKeyFile.*/SSLCertificateKeyFile \/etc\/letsencrypt\/live\/${domainname}\/privkey.pem/" /etc/apache2/sites-enabled/default-ssl.conf 7 sed -i "s/443/${sslport}/" /etc/apache2/sites-enabled/default-ssl.conf 8 sed -i "s/443/${sslport}/" /etc/apache2/ports.conf 9 10 apache2-foreground
This is the script that will be run whenever an instance of my Owncloud image is started. It basically does:
- Line 3: It sets up a letsencrypt certificate for my domain. The domainname needs to be passed with an environment variable. It will do this by launching a small webserver listening on port 443 and write a verification file that letsencrypt instructs it to do. This proves that I am the owner of my domain.
- Line 5-6: Changes Apache’s configuration to point to the ssl-certificates that was created in line 3.
- Line 7-8: Instead of the standard port 443 for the Owncloud webserver, I want to change it to my preferred port.
- Line 10: Finally apache is launched in foreground mode. This makes it possible for docker to get the log from the docker instance.
Backup Script
The last part of my image is a file called “backup-owncloud.sh” (remember to chmod 755):
1 #!/bin/bash 2 tmpdir=$(mktemp -d) 3 cd $tmpdir 4 5 mysqldump -h mysql -u root -p$MYSQL_ROOT_PASSWORD --all-databases > database-dump.sql 6 tar cvf backup.tar database-dump.sql >/dev/null 7 8 { echo /var/www/html/config ; \ 9 find /var/www/html/data -type d -name "files_encryption" ; } \ 10 | tar rvf backup.tar -T - >/dev/null 11 tar rvf backup.tar /etc/letsencrypt >/dev/null 12 13 cat backup.tar 14 15 rm -rf $tmpdir
I will use this script later on to take backups of the owncloud server configuration and encryption keys
- Line 5-6: Dumps the full mysql database and adds it to a tar-file
- Line 8-11: Adds the owncloud config files and the encryption keys to the tar file
- Line 13: Return the tarfile to stdout. This will be used later from the host-machine
Building the owncloud-image.
Now we are ready to start building our own version of owncloud. The following command pull’s the original Owncloud image and adds everything according to the Dockerfile:
root@owncloud# docker build -t alex/owncloud .
If everything goes fine, you should have two images:
root@owncloud# docker images alex/owncloud latest cbb6bf2a3743 8 minutes ago 811 MB owncloud latest 8720bc439c27 3 weeks ago 549 MB
Creating a compose-file to define how things should run
We now create a file called docker-compose.yml that looks like this:
1 version: '2' 2 3 services: 4 5 websvc: 6 restart: always 7 image: alex/owncloud 8 ports: 9 - 27572:27572 10 - 443:443 11 volumes: 12 - owncloud_www:/var/www/html 13 - owncloud_letsencrypt:/etc/letsencrypt 15 environment: 16 - MYSQL_ROOT_PASSWORD=looooong_password 17 - domainname=owncloud.example.com 18 - letsencrypt_email=admin@example.com 19 - sslport=27572 20 networks: 21 - owncloud_internal 22 23 mysql: 24 restart: always 25 image: mariadb 26 environment: 27 - MYSQL_ROOT_PASSWORD=looooong_password 28 volumes: 29 - owncloud_db:/var/lib/mysql 30 networks: 31 - owncloud_internal 32 33 volumes: 34 owncloud_www: 35 owncloud_letsencrypt: 36 owncloud_db: 37 38 networks: 39 owncloud_internal:
Basically this file sets up a mysql-server using the official mariadb docker image. And then an instance of the alex/owncloud image that we built previously. Here is what happens.
The web service:
- Line 6: After reboot the docker instance will be automatically started.
- Line 7: The instance is made from the previously built alex/owncloud image
- Line 8-10: Port 27572 on the hostmachine is directed to the docker-container. This is where I want my owncloud to reside. I also forward port 443 only for the purpose of getting certificates from letsencrypt.
- Line 11-13: I want to have persistent data when I update my image. So I am pointing to datacontainers (they will automatically be created by docker-compose)
- Line 16-19: I am passing environment variables to the docker container, with some setup of letsencrypt and apache. These variables are referred to in my two custom scripts
The mysql service:
- Line 25: This container is based on the official mariadb docker image
- Line 28-29: I want the Mysql database be persistent. Therefore I let docker compose create a persistent data-volume for this purpose.
For both services:
- Line 20-21, 30-31, 38-39: Sets up an internal network for both the webserver and the database. Only these two docker containers can talk to each other. They can talk to eachother via hostname (the hostnames defined in line 5 and 23)
- Line 11-13, 28-29, 33-36: Defines the persistent volumes that docker compose should create, the first time the environment i brought up.
Starting up the containers:
Being in the folder containing the docker-compose.yml file I run:
docker-compose up -d
I check that everything is running like it should:
root@owncloud# docker ps cea42737aaac mariadb "docker-entrypoint..." 30 minutes ago Up 30 minutes 3306/tcp owncloud_mysql_1 f80a3b41f3d5 alex/owncloud "/entrypoint.sh /s..." 30 minutes ago Up 30 minutes 0.0.0.0:443->443/tcp, 80/tcp, 0.0.0.0:27572->27572/tcp owncloud_websvc_1
I was now able to browse to https://owncloud.example.com:27572 from my favourite browser. For all this to work I made sure DNS for owncloud.example.com was pointing to my docker-host’s IP.
The first thing I entered was: username=admin, password=admin and pointed the database to host=mysql, user=root, password=looooong_password.
Now the Owncloud is configured and I have the green HTTPS-padlock in my browser.
I checked the logs from the webserver like this:
Docker logs owncloud_websrv_1
My first backup
docker exec -i owncloud_websvc_1 /backup-owncloud.sh > /var/backup/owncloud-backup.tar
I checked that everything was in the tarball. Now I am happy with my Owncloud-server 🙂