Automatic TLS 101 for Docker in 2021 - Using Traefik, Cloudflare, Let’s Encrypt and Namecheap¶
In this article we will be discussing reverse proxies, how they will enable you to securely expose webapps running on your LAN to the outside world, and how to automate issuing TLS (the artist formerly known as SSL) certificates using Let's Encrypt, Traefik, Cloudflare and Namecheap.
This guide was written for Traefik v2 (last modified date at the bottom of the page).
Traefik is the brains of the operation here acting as a middle man between multiple parties - your container(s), Let's Encrypt and Cloudflare. It is responsible for detecting when new containers have been created, communicating with Let's Encrypt to request a certificate to be issued and talking with Cloudflare by creating domain ownership verification records.
There are quite a few moving parts to this operation but in essence, it's a simple transaction - albeit one with quite a few steps.
I know the diagram above is a little small so please use the full resolution link if you need it.
One of the nice things about Traefik is that this process is largely transparent to the end user and configured by adding a few labels to each container like this:
nginx: image: nginx container_name: nginx-test labels: - traefik.enable=true - traefik.http.routers.nginx.rule=(Host(`nginx.perfectmediaserver.com`) - traefik.http.routers.nginx.entrypoints=websecure - traefik.http.routers.nginx.tls.certresolver=cloudflare
We'll come onto configuring Traefik itself a bit later on but the above snippet shows the configuration required for an nginx container to be exposed at
nginx.perfectmediaserver.com with an automatically generated TLS certificate from Cloudflare.
This approach of placing the configuration for the proxy in the compose file right alongside each container is one of the best things, in my opinion, about Traefik. With other reverse proxies, like nginx, there are multiple config files required which can be quite complicated to read. With this method, everything is in one place. Simple.
This guide assumes a few things are in place:
- You own your own domain such as "perfectmediaserver.com", purchasing a .com domain costs as little as $10 per year
- You have a Cloudflare account to use as your DNS provider (this is free)
- You have a single host running docker and a few containers
Traefik works best with a single primary container host. Those containers should be running on the same host you intend to run Traefik on. Not in a VM, not on a remote host, but the same OS. This is because Traefik watches the docker socket (the main entrypoint for the docker API) for changes so it knows when a container has been created, modified or destroyed.
The first component of this architecture is Traefik, a reverse proxy. The job of a reverse proxy is to listen for incoming requests, match that request to a rule, go get the requested content and finally serve it back to the user. This process is entirely transparent to the user and appears as if the target service is responding directly to you.
Traefik supports numerous providers for DNS challenge verification, but we will only be discussing Cloudflare in the scope of this article. Using Cloudflare for DNS is free. You are welcome to use other DNS providers, but will need to adjust these steps according to Traefik's provider documentation if you do.
A simple start¶
Let's use nginx as a simple example for the bare minimum code required for a working configuration:
--- version: "2" services: traefik: image: traefik container_name: tr volumes: - /home/alex/appdata/traefik/letsencrypt:/letsencrypt - /var/run/docker.sock:/var/run/docker.sock:ro ports: - 80:80 - 443:443 environment: - [email protected] - CLOUDFLARE_API_KEY=CFglobalAPIkey command: - --providers.docker=true - --entrypoints.web.address=:80 - --entrypoints.web.http.redirections.entryPoint.to=websecure - --entrypoints.web.http.redirections.entryPoint.scheme=https - --entrypoints.websecure.address=:443 - --certificatesresolvers.cloudflare.acme.dnschallenge=true - --certificatesresolvers.cloudflare.acme.dnschallenge.provider=cloudflare - [email protected] - --certificatesresolvers.cloudflare.acme.storage=/letsencrypt/acme.json nginx: image: nginx container_name: nginx-test labels: - traefik.http.routers.nginx.rule=Host(`nginx.perfectmediaserver.com`) - traefik.http.routers.nginx.tls.certresolver=cloudflare
Using this configuration we'll end up with an nginx container running at
nginx.perfectmediaserver.com with a valid TLS certificate, like this:
In this example I used Cloudflare but you can use any other DNS provider from this list provided by Traefik. If using another provider replace
CLOUDFLARE_* environment variables with those suitable for your provider.
Domain Setup - Namecheap¶
There are many options out there for domain registrars but I have used namecheap for over a decade now. It's considered good practice (though not required) to register your domain in a different place from where the DNS nameservers resides. To configure a namecheap domain to work with Cloudflare first we need to login to our namecheap dashboard and click
NAMESERVERS clear out all existing values and select
The values you will need to enter into this section can be found over at your Cloudflare account as shown here.
These will most likely be different from the ones shown below, that is normal. Just input them into namecheap and wait for DNS propagation to work.
To test the nameservers we can use
dig perfectmediaserver.com NS:
$ dig perfectmediaserver.com NS ; <<>> DiG 9.16.1-Ubuntu <<>> perfectmediaserver.com NS ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 22411 ;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 65494 ;; QUESTION SECTION: ;perfectmediaserver.com. IN NS ;; ANSWER SECTION: perfectmediaserver.com. 41321 IN NS gabe.ns.cloudflare.com. perfectmediaserver.com. 41321 IN NS kia.ns.cloudflare.com. ;; Query time: 0 msec ;; SERVER: 127.0.0.53#53(127.0.0.53) ;; WHEN: Tue Sep 07 00:58:46 UTC 2021 ;; MSG SIZE rcvd: 102
This can take up to 24h so be patient and be sure not to spam Let's Encrypt with requests from Traefik in the meantime else you may get locked out for up to a week by rate limiting.
Let's Encrypt Staging API¶
Whilst you are first trying all this stuff out it might be a good idea to use the Let's Encrypt staging API so that you don't fall victim of rate limiting lock outs. With Traefik, add this line into the list of
Traefik and the Docker provider¶
Traefik creates a corresponding service and router for each container. This is a long and potentially complex topic to understand but comprehension is not a pre-requisite for usage to begin with.
Full documentation on the provider can be found here.
Traefik and TLS apps (like Unifi)¶
Apps like Ubiquiti's Unifi software can be run as a container and do so over TLS locally almost always using a self-signed TLS certificate. This breaks the default model used by Traefik which expects plain http traffic. We can set
insecureSkipVerify=true as a
command parameter to tell Traefik to ignore the self-signed certs. The full configuration line looks like this:
Traefik and declaring ports¶
Traefik relies on apps to have the correct ports exposed in its Dockerfile. We can override this or expose multiple ports using this label applied to the container itself:
A more complete example¶
You can find a more complex docker-compose example in my infra repo here.