Traefik, Let's Encrypt and Docker Compose
Update 2019/11/29: This article only applies to Traefik v1. V2 has a different flags and a slightly different frontend/router setup. I will update this post eventually!
I'm a huge fan of Docker and Let's Encrypt. It's a dream come true for someone who manages their family and friends' Wordpress sites - just set up a container and let them have at it.
Lately I've been making use of the reverse proxy Traefik. One of the coolest features about it is that it can dynamically configure itself based on the labels you give to a Docker container, and can also automatically fetch certificates from Let's Encrypt.
A Simple Example
Let's say you have a docker-compose file running your website:
version: "2"
services:
website:
image: mywebsite
ports:
80:5000
Something along those lines. If you wanted to have SSL support you have a couple of options: one, run something like Nginx within your docker container and map certificates in from outside the container, for example:
version: "2"
services:
website:
image: mywebsite
ports:
80:5000
443:5001
volumes:
- ${PWD}/cert.pem:/usr/share/nginx/certs/cert.pem
- ${PWD}/cert.cer:/usr/share/nginx/certs/cert.cer
This is fine but kind of a pain to manage, and anything configuration management we have outside of the Docker containers puts more reliance on configuration management tools like Ansible or Puppet or what-have-you.
Getting Traefik to work
Traefik comes in the form of a docker image, so we can just plop it into our docker-compose file. It does need some external configuration. Here's a really boiled down example that should give you all you need:
traefikLogsFile = "/var/log/traefik/traefik.log"
logLevel = "INFO"
defaultEntryPoints = ["http", "https"]
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.http.redirect]
entryPoint = "https"
[entryPoints.https]
address = ":443"
[entryPoints.https.tls]
[acme]
email = "your-email@gmail.com"
storage = "/etc/traefik/acme/acme.json"
entryPoint = "https"
dnsProvider = "digitalocean"
[[acme.domains]]
main = "yoursite.com"
sans = ["www.yoursite.com", "web.yoursite.com"]
That's actually pretty close to what I use to run my site. It tells Traefik to listen on both port 80 and 443, but to redirect all HTTP requests to HTTPS. It also configures Let's Encrypt (the acme sections) with the DigitalOcean DNS providers to do the challenge-response. Finally we tell it which domains to try and register the cert with, as well as which SAN's to associate the cert with. You can have up to 100 SAN's for one cert with Let's Encrypt!
Now we just configure the docker compose file:
version: "2"
service:
website:
image: mywebsite
labels:
traefik.port: "5000"
traefik.frontend.rule: "Host: yoursite.com, www.yoursite.com, web.yoursite.com"
traefik:
image: traefik
command: --docker
environment:
DO_AUTH_TOKEN: "SOMEAUTHTOKEN"
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /var/log/traefik:/var/log/traefik
- ${PWD}/traefik.toml:/etc/traefik/traefik.toml
- ${PWD}/acme:/etc/traefik/acme
The traefik service is a little long but that's it - we just map the Docker socket so that Traefik can use Docker labels for configuration, we map our traefik.toml file in, and then map the Acme directory in so that even if we restart Traefik, it won't lose info on which certificates it's registered.
We also have the DigitalOcean auth token so that Traefik can update your DNS for the challenge-response, and then finally set the Docker labels for your website container.
You can find all the labels you can pass in to your container that Traefik will understand by checking out the Traefik docs here. The documentation is pretty nice, but could stand to have some more simple examples.
You can even use the traefik.frontend.auth.basic
label to set up some simple
authentication for your service!