Traefik v2 Using Docker
What is traefik?
Traefik is an open-source edge router and reverse proxy that manages and routes traffic to services dynamically. It integrates with technologies like Docker and Kubernetes, automatically detects changes, supports multiple protocols (HTTP, HTTPS, TCP, WebSocket), and includes features like automatic SSL/TLS certificates from Let's Encrypt (sometimes a pain in the ass). Traefik also offers middlewares for added functionalities and extensive observability through metrics and logs, making it ideal for scalable, high-traffic microservices environments.
Installing and using traefik as a reverse proxy (with SSL/TLS)
I only use traefik as a reverse proxy and SSL/TLS for this site. You may also know that nginx has a reverse proxy manager as well but I find traefik to be easier to use and I like the web UI more as well. I may add some middlewares in the future but at the moment, I don't feel like it. Anyways, for Docker containers I prefer using a configuration file and docker compose to spin up containers. You could also spawn containers using commands or a DockerFile (similar to the configuration file + compose method) but I prefer yaml so I will be doing that over DockerFile.
This is what my full traefik docker-compose.yml
looks like:
1version: "3" 2 3services: 4 reverse-proxy: 5 container_name: traefik 6 image: traefik:v2.11.6 7 ports: 8 # The HTTP port 9 - "80:80" # web 10 - "443:443" # websecure 11 # The Web UI port 12 - "8081:8080" 13 volumes: 14 # Config file 15 - /etc/traefik/traefik.yaml:/etc/traefik/traefik.yaml 16 # So that Traefik can listen to the Docker events 17 - /var/run/docker.sock:/var/run/docker.sock 18 # For TLS certs not to be re-generated every time... 19 - /etc/traefik/certs/acme.json:/acme.json 20 networks: 21 - nginx 22 23networks: 24 nginx: 25 external: true
Let's break this up into a few pieces and talk about what's going on here. Firstly, I know that the "version" property has been deprecated but I still use it anyways, feel free to omit that in your own config files. That being said, we have our services which is just traefk in this case with the container_name: traefik
so that it looks clean in docker ps
and Portainer. The image I am using is v2.11.6
.
1 ... 2 ports: 3 # The HTTP port 4 - "80:80" # web 5 - "443:443" # websecure 6 # The Web UI port 7 - "8081:8080" 8 ...
These are pretty self-explanatory. I want people who still, for some reason, use http to be able to access my stuff so that's why port 80 is there. Port 443 is https and 8081 is the port I set to access the traefik web ui, with the internal port of 8080. You can use whatever port you want, assuming it's not being used for something else. In my case, I have qBittorrent on port 8080 so I'm using port 8081 here.
1 ... 2 volumes: 3 # Config file 4 - /etc/traefik/traefik.yaml:/etc/traefik/traefik.yaml 5 # So that Traefik can listen to the Docker events 6 - /var/run/docker.sock:/var/run/docker.sock 7 # For TLS certs not to be re-generated every time... 8 - /etc/traefik/certs/acme.json:/acme.json 9 ...
These are the volume binds that I have set up. Notice that there is another traefik.yaml
file that the container is using, that's where the rest of the set up for traefik is. Here is what that file looks like:
1global: 2 checkNewVersion: true 3 sendAnonymousUsage: false 4 5# -- (Optional) Change Log Level and Format here... 6# - loglevels [DEBUG, INFO, WARNING, ERROR, CRITICAL] 7# - format [common, json, logfmt] 8log: 9 level: DEBUG 10 format: common 11 filePath: /var/log/traefik/traefik.log 12 13# -- (Optional) Enable Accesslog and change Format here... 14# - format [common, json, logfmt] 15accesslog: 16 format: common 17 filePath: /var/log/traefik/access.log 18 19# -- (Optional) Enable API and Dashboard here, don't do in production 20api: 21 dashboard: true 22 insecure: true 23 24entryPoints: 25 web: 26 address: :80 27 # -- (Optional) Redirect all HTTP to HTTPS 28 http: 29 redirections: 30 entryPoint: 31 to: websecure 32 scheme: https 33 websecure: 34 address: :443 35 36certificatesResolvers: 37 staging: 38 acme: 39 email: a.mehraz.cs@gmail.com 40 storage: /etc/traefik/certs/acme.json 41 caServer: "https://acme-staging-v02.api.letsencrypt.org/directory" 42 httpChallenge: 43 entryPoint: web 44 45 production: 46 acme: 47 email: a.mehraz.cs@gmail.com 48 storage: /etc/traefik/certs/acme.json 49 caServer: "https://acme-v02.api.letsencrypt.org/directory" 50 httpChallenge: 51 entryPoint: web 52 53providers: 54 docker: 55 # -- (Optional) Enable this, if you want to expose all containers automatically 56 exposedByDefault: false 57 file: 58 directory: /etc/traefik 59 watch: true
I don't feel like going through every single piece and this is also not everything you are able to set up but it's what I have. Also, yes, I know my email is there. The main parts are the entrypoints for http and https which I named web
and websecure
, the redirecting from http to https, and the TLS certificate generation and storage from Let's Encrypt (using an http challenge). Again, there are more options that are available to you for that like DNS Challenge with a DNS provider or TLS challenge. Learn more about that here.
Updates
Any updates being made will be below.
18 July 2024
I have updated my traefik configuration to use my SSL certs from Porkbun instead of the one that traefik generates. This was mostly because I wanted to know how to add my own SSL certs if in the future I did not want to use Let's Encrypt. Porkbun actually generates the cert from Let's Encrypt so I still am using them but I cared about the part where I actually tell traefik to use a particular cert and key, not really caring where/who it is sourced from. In any case, the changes I made to traefik.yaml
include:
1certificatesResolvers: 2 staging: 3 acme: 4 email: a.mehraz.cs@gmail.com 5 storage: /etc/traefik/certs/acme.json 6 caServer: "https://acme-staging-v02.api.letsencrypt.org/directory" 7 httpChallenge: 8 entryPoint: web 9 10 production: 11 acme: 12 email: a.mehraz.cs@gmail.com 13 storage: /etc/traefik/certs/acme.json 14 caServer: "https://acme-v02.api.letsencrypt.org/directory" 15 httpChallenge: 16 entryPoint: web
1certificatesResolvers: 2 porkbun: 3 acme: 4 email: "a.mehraz.cs@gmail.com" 5 storage: "/etc/traefik/certs/acme.json" 6 dnsChallenge: 7 provider: porkbun 8 delayBeforeCheck: 90 # Optional, useful if DNS propagation is slow 9 production: 10 acme: 11 email: a.mehraz.cs@gmail.com 12 storage: /etc/traefik/certs/acme.json 13 caServer: "https://acme-v02.api.letsencrypt.org/directory" 14 httpChallenge: 15 entryPoint: web 16 17# -- Overwrites Default Certificates (above) 18tls: 19 stores: 20 default: 21 defaultCertificate: 22 certFile: certs/fullchain.pem 23 keyFile: certs/private.key.pem
I left the redundant porkbun
field in the certificatesResolvers
since I was using it earlier but for some reason the acme.json
file never got propagated correctly. Instead I downloaded my SSL Bundle from Porkbun which includes the certificate for my domain, my public key, my private key, and the intermediate certificate. You typically only need the primary certificate and the private key. However, to ensure a complete chain of trust, you should combine your primary certificate (domain.cert.pem
) and the intermediate certificate (intermediate.cert.pem
) into a single file. Here’s how to combine those files and place it in traefik's certs directory:
1cat domain.cert.pem intermediate.cert.pem > fullchain.pem && cp fullchain.pem /etc/traefik/certs/
Note: The public.key.pem file is generally not needed for SSL/TLS configuration in Traefik.
Now that the full certificate is where I want it, I then copied the private key into the same place as well:
1cp private.key.pem /etc/traefik/certs/
I then made sure the permissions were correct
1sudo chown 65532:65532 /etc/traefik/certs/fullchain.pem /etc/traefik/certs/private.key.pem 2sudo chmod 600 /etc/traefik/certs/fullchain.pem /etc/traefik/certs/private.key.pem
All that was left was to edit the traefik docker compose file to include my cert
1 ... 2 volumes: 3 ... 4 # Mount SSL certificates 5 - /etc/traefik/certs/fullchain.pem:/certs/fullchain.pem 6 - /etc/traefik/certs/private.key.pem:/certs/private.key.pem 7 ...
Now traefik is able to use my SSL cert instead of one that is generated from traefik. I then told my nginx webserver to use this cert, see more in the update of my nginx post.