What is traefik? Link to heading
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) Link to heading
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:
version: '3'
services:
reverse-proxy:
container_name: traefik
image: traefik:v2.11.6
ports:
# The HTTP port
- "80:80" # web
- "443:443" # websecure
# The Web UI port
- "8081:8080"
volumes:
# Config file
- /etc/traefik/traefik.yaml:/etc/traefik/traefik.yaml
# So that Traefik can listen to the Docker events
- /var/run/docker.sock:/var/run/docker.sock
# For TLS certs not to be re-generated every time...
- /etc/traefik/certs/acme.json:/acme.json
networks:
- nginx
networks:
nginx:
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
.
...
ports:
# The HTTP port
- "80:80" # web
- "443:443" # websecure
# The Web UI port
- "8081:8080"
...
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.
...
volumes:
# Config file
- /etc/traefik/traefik.yaml:/etc/traefik/traefik.yaml
# So that Traefik can listen to the Docker events
- /var/run/docker.sock:/var/run/docker.sock
# For TLS certs not to be re-generated every time...
- /etc/traefik/certs/acme.json:/acme.json
...
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:
global:
checkNewVersion: true
sendAnonymousUsage: false
# -- (Optional) Change Log Level and Format here...
# - loglevels [DEBUG, INFO, WARNING, ERROR, CRITICAL]
# - format [common, json, logfmt]
log:
level: DEBUG
format: common
filePath: /var/log/traefik/traefik.log
# -- (Optional) Enable Accesslog and change Format here...
# - format [common, json, logfmt]
accesslog:
format: common
filePath: /var/log/traefik/access.log
# -- (Optional) Enable API and Dashboard here, don't do in production
api:
dashboard: true
insecure: true
entryPoints:
web:
address: :80
# -- (Optional) Redirect all HTTP to HTTPS
http:
redirections:
entryPoint:
to: websecure
scheme: https
websecure:
address: :443
certificatesResolvers:
staging:
acme:
email: a.mehraz.cs@gmail.com
storage: /etc/traefik/certs/acme.json
caServer: "https://acme-staging-v02.api.letsencrypt.org/directory"
httpChallenge:
entryPoint: web
production:
acme:
email: a.mehraz.cs@gmail.com
storage: /etc/traefik/certs/acme.json
caServer: "https://acme-v02.api.letsencrypt.org/directory"
httpChallenge:
entryPoint: web
providers:
docker:
# -- (Optional) Enable this, if you want to expose all containers automatically
exposedByDefault: false
file:
directory: /etc/traefik
watch: true
* See 18 July 2024 Update*
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 Link to heading
Any updates being made will be below. Here is a table with jumps to various dates with a short description of changes made:
Date: Short description
18 July 2024: Changes to SSL
18 July 2024 Link to heading
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:
certificatesResolvers:
staging:
acme:
email: a.mehraz.cs@gmail.com
storage: /etc/traefik/certs/acme.json
caServer: "https://acme-staging-v02.api.letsencrypt.org/directory"
httpChallenge:
entryPoint: web
production:
acme:
email: a.mehraz.cs@gmail.com
storage: /etc/traefik/certs/acme.json
caServer: "https://acme-v02.api.letsencrypt.org/directory"
httpChallenge:
entryPoint: web
to ↓
certificatesResolvers:
porkbun:
acme:
email: "a.mehraz.cs@gmail.com"
storage: "/etc/traefik/certs/acme.json"
dnsChallenge:
provider: porkbun
delayBeforeCheck: 90 # Optional, useful if DNS propagation is slow
production:
acme:
email: a.mehraz.cs@gmail.com
storage: /etc/traefik/certs/acme.json
caServer: "https://acme-v02.api.letsencrypt.org/directory"
httpChallenge:
entryPoint: web
# -- Overwrites Default Certificates (above)
tls:
stores:
default:
defaultCertificate:
certFile: certs/fullchain.pem
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 prepare the files for Traefik:
cat 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:
cp private.key.pem /etc/traefik/certs/
I then made sure the permissions were correct
sudo chown 65532:65532 /etc/traefik/certs/fullchain.pem /etc/traefik/certs/private.key.pem
sudo 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
...
volumes:
...
# Mount SSL certificates
- /etc/traefik/certs/fullchain.pem:/certs/fullchain.pem
- /etc/traefik/certs/private.key.pem:/certs/private.key.pem
...
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.