Docker Series Pt.2: Set up ownCloud + Traefik as a Reverse Proxy with Let’s Encrypt SSL
Docker is an easy and powerful way to set up ownCloud, making it easy to extend the architecture. The reverse proxy Traefik, for example, integrates other services and can provide Let’s Encrypt SSL certificates.
In the first blog post of this series you learned how to set up ownCloud with docker-compose. This tutorial builds on this knowledge to build an advanced docker setup. Docker can do far more than just setting up containers, it also makes communication between containers easier.
A reverse proxy is useful in many ways. You can integrate multiple services easily in your setup, while they are reachable with only one public IP. It can also provide and automate Let’s Encrypt SSL certificates – for all your services.
Using Traefik has many advantages: it is easy to set up, it has a useful web interface, and it’s specifically designed to work with docker containers.
This guide explains how to set up Docker with Traefik and integrate an ownCloud into it. Integrating other docker images like WordPress, Jitsi, Mailman, or Collabora works in a similar way… try it out and play around!
The First Steps
This guide assumes that you already have docker-compose installed on your machine. If you haven’t, just follow these official instructions for your operating system.
First you have to create a network for all services which should be reachable from the Internet. We then need to define it outside of a docker-compose file, as we want to use it for multiple docker-compose files:
docker network create web
This way, your database containers are protected. Not even Traefik can see them, they will all get their own internal network later, one for each service.
Then we will set up our working directory. You can also use another place on the system, but then you will have to change all the paths in this guide.
mkdir -p /opt/traefik touch /opt/traefik/docker-compose.yml touch /opt/traefik/acme.json && chmod 600 /opt/traefik/acme.json touch /opt/traefik/traefik.toml
Let’s also assume that you have bought a domain which is pointing to the IP address of your server. Each of your services will need a subdomain, but they can all point to the same IP. Here’s an example:
In this guide, the domain and subdomains are example.com, traefik.example.com, and owncloud.example.com – you will need to exchange it with your domain name when you are copy-pasting the docker-compose and config files.
Define the Traefik Container
Now we will set up Traefik. First create and edit the traefik docker-compose file with
version: '2' services: proxy: # You might want to use a proper version image: traefik command: --configFile=/traefik.toml restart: unless-stopped # Here's the network we created: networks: - web # The traefik entryPoints ports: - 80:80 - 443:443 labels: - traefik.enable=true - traefik.frontend.rule=Host:traefik.example.com # Traefik will proxy to its own GUI. - traefik.port=8080 - traefik.docker.network=web volumes: - /var/run/docker.sock:/var/run/docker.sock - /opt/traefik/traefik.toml:/traefik.toml - /opt/traefik/acme.json:/acme.json networks: web: external: true
You should of course replace example.com in the docker-compose file with your own domain name.
The Traefik Config File
Traefik has a toml config file to manage entry points, Let’s Encrypt settings, and the web interface. Create the traefik config file with
# uncomment this line to get debug info with "docker logs": #debug = true defaultEntryPoints = ["https","http"] # The syntax is somewhat esoteric so this is mostly copy-paste [entryPoints] [entryPoints.http] address = ":80" [entryPoints.http.redirect] entryPoint = "https" [entryPoints.https] address = ":443" [entryPoints.https.tls] [docker] endpoint = "unix:///var/run/docker.sock" domain = "example.com" watch = true exposedbydefault = false [acme] email = "firstname.lastname@example.org" storage = "/acme.json" # problems with let's encrypt? You can use this staging environment, # if you have to do a lot of trial and error: #caServer = "https://acme-staging-v02.api.letsencrypt.org/directory" entryPoint = "https" OnHostRule = true [acme.httpChallenge] entryPoint = "http" # enable web configuration backend. [web] # Web administration port, proxied in docker-compose.yml address = ":8080"
You need to add your domain and email address at [docker] and [acme], so that the config file works for you. The values you have to change are in bold.
This traefik.toml automatically fetches a Let’s Encrypt SSL certificate, and also redirects all unencrypted HTTP traffic to port 443. This way, no one accidentally accesses your ownCloud without encryption.
Now we are good to go! Run the container with
docker-compose -f /opt/traefik/docker-compose.yml up -d. And that’s it!
If Let’s Encrypt doesn’t work out of the box, you may have to do some troubleshooting. Note that Let’s Encrypt blocks certificate requests if you try too often; that’s why you can use the alternative caServer option in traefik.toml.
If you uncomment it, Traefik asks the Let’s Encrypt staging server for an (untrusted) certificate. When you get that to work, you can then comment out the caServer option again, so it uses the default server for fetching trusted certificates. Good luck troubleshooting!
If it works, you can visit traefik.example.com to look at the web interface. It should look like this:
Add Basic Authentication for Traefik
If you want to expose the Traefik web interface, you would probably like to have some form of authentication. Basic auth is supported so let’s add that. Run this for the username you want – for example admin – and enter your password. It will compute a hash of the password, which you can use in the docker-compose file:
htpasswd -n username
Here’s what I got for admin/admin:
(Don’t use admin/admin as a password combination. Every hacker tries that first.)
Now that needs to go in the docker-compose.yml. Add this to the labels-section: (Note: any $ signs have to be escaped with another $.)
labels: - "traefik.frontend.auth.basic=admin:$$apr1$$IBj9Hfsd$$kf7vXLpY4/9XD365jcp/n1"
Rebuild your container with
docker-compose -f /opt/traefik/docker-compose.yml up -d and now you should have basic auth! Just visit traefik.example.com again – and you will be prompted for a password.
Now you have a running Traefik container, with a secured web interface, where you can watch the containers that Traefik is handling.
Add the ownCloud Containers
Now let’s add an ownCloud to this setup. We’ve already covered the ownCloud docker-compose file in the last blogpost, biut now you will learn how to integrate it here.
First, create a folder for ownCloud and edit the docker-compose.yml with
mkdir /opt/ownCloud vim /opt/ownCloud/docker-compose.yml
You can use this as an example, but you should use your own domain instead of example.com and change any insecure default passwords. Everything you have to change is in bold here:
version: '2.1' volumes: files: driver: local mysql: driver: local backup: driver: local redis: driver: local services: owncloud: image: owncloud/server:10.0 restart: unless-stopped depends_on: - db - redis environment: - OWNCLOUD_DOMAIN=owncloud.example.com - OWNCLOUD_DB_TYPE=mysql - OWNCLOUD_DB_NAME=owncloud - OWNCLOUD_DB_USERNAME=owncloud - OWNCLOUD_DB_PASSWORD=owncloud - OWNCLOUD_DB_HOST=db - OWNCLOUD_ADMIN_USERNAME=admin - OWNCLOUD_ADMIN_PASSWORD=admin - OWNCLOUD_UTF8MB4_ENABLED=true - OWNCLOUD_REDIS_ENABLED=true - OWNCLOUD_REDIS_HOST=redis networks: - web - internal labels: - traefik.enable=true - traefik.frontend.rule=Host:owncloud.example.com - traefik.port=80 - traefik.docker.network=web healthcheck: test: ["CMD", "/usr/bin/healthcheck"] interval: 30s timeout: 10s retries: 5 volumes: - files:/mnt/data db: image: webhippie/mariadb:latest restart: unless-stopped environment: - MARIADB_ROOT_PASSWORD=owncloud - MARIADB_USERNAME=owncloud - MARIADB_PASSWORD=owncloud - MARIADB_DATABASE=owncloud - MARIADB_MAX_ALLOWED_PACKET=128M - MARIADB_INNODB_LOG_FILE_SIZE=64M - MARIADB_INNODB_LARGE_PREFIX=ON - MARIADB_INNODB_FILE_FORMAT=Barracuda healthcheck: test: ["CMD", "/usr/bin/healthcheck"] interval: 30s timeout: 10s retries: 5 volumes: - mysql:/var/lib/mysql - backup:/var/lib/backup networks: - internal redis: image: webhippie/redis:latest restart: unless-stopped environment: - REDIS_DATABASES=1 healthcheck: test: ["CMD", "/usr/bin/healthcheck"] interval: 30s timeout: 10s retries: 5 volumes: - redis:/var/lib/redis networks: - internal networks: web: external: true internal:
If you read carefully, you will notice that we only expose port 80 for the ownCloud container. How does this fit with using SSL certificates?
Well, the ownCloud container does not communicate with the outside at all – only with the Traefik container. Traefik does not need to encrypt the traffic to the ownCloud container and vice versa, they are on the same machine anyway. As Traefik handles the SSL encryption, ownCloud does not even need to know that users are accessing it encrypted.
You can run the container with
docker-compose -f /opt/ownCloud/docker-compose.yml up -d and then ownCloud starts! As soon as the health test at
docker ps shows the ownCloud container as being healthy, Traefik will start routing to it. You can check if your ownCloud works at owncloud.example.com.
Congratulations! You just set up ownCloud with Traefik. What’s next?
Play Around with Docker!
When you have integrated some services and have a cool docker-compose file for your setup, why not share it, so that everyone can learn from it? This way, others have an easier time setting it up – or can point out where you can improve your setup.
Did you encounter problems with this guide? You can always ask in the comments for advice. And if you made it through this how-to easily, share your success on social media!
A big warm thank you to Jon Neverland for his blogpost Traefik with Docker and Let’s encrypt