January 20, 2026
My docker containers are served by Traefik reverse proxy
A reverse proxy is a single place where all traffic enters your network. This has a lot of benefits in a Docker environment:
- You can configure a custom domain name for every container application and have the reverse proxy handle the routing
- You can setup a single SSL/TLS certificate that secures traffic for all your application over HTTPS, and redirect all unsecure HTTP to HTTPS
- You can even add an authentication layer to applications so they can only be accessed with a username and password, something i have not touched yet
- More…
Setting up Traefik
Preparations
Make sure you have docker and docker compose installed.
I decided to use local self-signed SSL certificates because the encryption is purely for the traffic in my LAN. I have a blog post that explains how to generate these certificates and make your browser trust them on Windows and Iphone. If you want to use a certificate authority like Let’s Encrypt, the Traefik docs has this documented well.
Deploying
Create a network for your Traefik container and the containers to be routed by the reverse proxy, so they can communicate with each other:
docker network create proxyLet’s create a config file for traefik. I put mine in the /config folder and named it traefik.yaml:
global:
checkNewVersion: false
sendAnonymousUsage: false
log:
level: INFO
accesslog: true
api:
dashboard: true
insecure: false
entryPoints:
web:
address: :80
http:
redirections:
entryPoint:
to: websecure
scheme: https
permanent: true
websecure:
address: :443
providers:
docker:
exposedByDefault: false
network: proxy
file:
directory: /dynamic
watch: trueBrief explanation for the most important configurations:
- The
apihas its entrydashboardset to true to deploy the UI dashboard for Traefik. Theinsecureentry is set to false to server it with secure HTTPS - In
entryPointswe have thewebentry that configures port 80 to be redirected to thewebsecurescheme, which is bound to port 443. In other words, HTTP is redirected to HTTPS. - The
providersentry specifies adockerprovider with network proxy, which we created earlier. It also hasexposedByDefaultset to false. This means Traefik does not route traffic for a container by default, we have to explicitly configure this. - The
fileprovider is configured to watch the folder with the dynamic configuration, where my certificates are stored. We will configure this next.
In the /dynamic folder, create tls.yaml. This file defines the paths to the self-signed certificates inside the container:
tls:
certificates:
- certFile: /certs/wildcard.server.home.crt
keyFile: /certs/wildcard.server.home.keyTo put it all together, we create the compose.yaml :
services:
traefik:
container_name: traefik
image: traefik:v3.6
ports:
- "80:80"
- "443:443"
- "8080:8080"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro # Docker socket
- ./config/traefik.yaml:/etc/traefik/traefik.yaml:ro
- ./dynamic:/dynamic:ro
- ./config/certs:/certs:ro
networks:
- proxy
restart: unless-stopped
labels:
- "traefik.enable=true"
# Dashboard router
- "traefik.http.routers.dashboard.rule=Host(`$TRAEFIK_DASHBOARD_DOMAIN`)"
- "traefik.http.routers.dashboard.entrypoints=websecure"
- "traefik.http.routers.dashboard.service=api@internal"
- "traefik.http.routers.dashboard.tls=true"
# Basic‑auth middleware
- "traefik.http.middlewares.dashboard-auth.basicauth.users=$USER:$PASSWORDHASH"
- "traefik.http.routers.dashboard.middlewares=dashboard-auth@docker"
networks:
proxy:
external: trueWe expose ports 80 and 443 for Traefik to accept al HTTP and HTTPS traffic, after which tt can route the traffic to the corresponding container. Port 8080 is exposed for dashboard access.
We mount the Docker socket to a location inside the container so Traefik can dynamically configure other containers according to docker labels. Also mounted are the aforementioned Traefik.yaml file and /dynamic directory.
The location of your SSL certificates need to be mounted to /certs.
We use the proxy network that we created earlier. All the new containers that you want to put behind the reverse proxy also need to use this network.
Finally, the Traefik labels are defined. Replace $TRAEFIK_DASHBOARD_DOMAIN with the domain you want for the dashboard. If you prefer your dashboard to be secured with a username and password, you can generate the $USER:$PASSWORDHASH string with the following command, using your preferred credentials:
htpasswd -nb admin passwordIf you dont need authentication you can remove the two labels for the basic-auth middleware.
Deploy the container by executing the following command in the directory with the compose.yaml:
docker compose up -dThat’s it! Your dashboard should be accessible with your custom domain. Enjoy 🚀🚀🚀
A Final Remark
Final words for the mega struggle i had to make Traefik work in my setup. Watched and read so many how-to tutorials but couldn’t get it to work. I got 404 not found errors for every domain i tried to setup with Traefik.
Turned out i forgot about the K3s cluster that i had started on my server to practice Kubernetes for the CKAD certification i passed (😎) a month ago. The cluster occupied port 80 while my Linux machine and Traefik were both convinced that the port was open. Actually also tried Nginx reverse proxy and Caddy while desperately looking for something that worked, but Traefik got lucky to be the one i worked on while stumbling upon the cause of the problem.