In part 3 of my Dockerize-Me series I’ve been looking at how to run several web services on the same server, make them accessible on the same ports (80 for http and 443 for https) and add Letsencrypt TLS certificates for secure communication. This is typically done with a reverse http proxy setup as described in episode 3 (in Docker containers of course…). In the feedback, several people suggested that I should also look at Traefik as another alternative. So as I like choice, I did just that.
Unlike the setup in episode 3, which just does one thing, and does it well, i.e. acting as a reverse proxy without bells and whistles, Traefik is a mega-supertanker in the web frontend world which, among many other things, can also be used as a reverse proxy with Letsencrypt integration. The documentation looks like fun and while it probably describes the mega-supertanker well for super-tanker captains, I only wanted to know about the small sailing boat features (i.e. the reverse proxy + Letencrypt functions) and not how to operate a supertanker. There are lots of descriptions on the net of how to use this particular part of Traefik but most of them are outdated and end up in bizarre error messages or they are lacking a vital part of the story for use in production. But finally I found this article which contains almost everything I needed without any crud:
- Simple config files;
- How Letsencypt works in a simple setup;
- How to use Traefik’s management console over https with its own domain name instead of over an unencrypted connection on a separate port without any access controls;
- Which labels to add to existing containers to make them work with Traefik.
While this article contains almost everything, there are the following ‘nice to have’ things that I would like to add:
One thing I was not happy with was that a rather long docker command is used to start the reverse proxy with many command-line options. So I created the following docker-compose.yml file to make life a bit easier on that front:
version: '3.3'
services:
traefik:
image: traefik:2.4
restart: always
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./traefik.toml:/traefik.toml
- ./traefik_dynamic.toml:/traefik_dynamic.toml
- ./acme.json:/acme.json
ports:
- "80:80"
- "443:443"
networks:
- web
networks:
web:
external: true
Also, I have switched from Traefik v2.2 to v2.4 as the world has moved on. Fortunately, the parameters used in the configuration files did not change in the meantime.
The other thing that I didn’t like is that out of the box, Traefik only gets a ‘B’ in SSL Labs Server Tests for transport security. My other solution from part 3 gets an ‘A+’ without changing anything. Not acceptable! So after a bit of searching, I realized that I could add the tls.options configuration required to limit the number of cipher suites to the traefik_dynamic.toml file. It now looks like this:
[http.middlewares.simpleAuth.basicAuth]
users = [
"john:$apr1$vWxgDtnh$hdhheDsJWRn7B027dHlDH."
]
[http.routers.api]
rule = "Host(tr-monitor.
MYDOMAIN.COM)"
entrypoints = ["websecure"]
middlewares = ["simpleAuth"]
service = "api@internal"
[http.routers.api.tls]
certResolver = "lets-encrypt"
[tls.options]
[tls.options.default]
minVersion = "VersionTLS12"
cipherSuites = [
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
]
And finally, here’s a screenshot of the additions that have to be made to a docker-compose.yml project file to use Traefik as a front end. The idea is the same as in the easier solution described in part 3: Labels (or environment variables in the other approach) are added to the container descriptions that can be picked up by the Traefik container so internal network routes can be created and Letsencrypt certificates can be fetched if required.
The important part that must not be forgotten is to use a different router name (e.g. ‘drdb’ in the example) for each container on the server that uses Traefik. This is easily overlooked!
And that’s it! And while it took me a few hours to get all of this together, I hope this summary will shorten the process for you!
Thank you! I’ve looked into trying traefik but never managed to get it working, and after a few hours I just gave up and went back to nginx.