Enable SSL using Traefik
⚠️ Please note: These notes are for myself only as it assumes a lot of things that are tailored to my setup and which aren’t made explicit. Please find a better guide in case you come across this page.
Suppose you want to set up HTTPS for a web application you’re serving via Traefik. For simplicity, let’s assume you’re using Docker Compose in production. Here’s how you can go about it.
Create a separate docker-compose.prod.yml
file for the production version of Traefik
Suppose you have this docker-compose.yml
file in your Git repo that provides the Traefik Docker service for your development environment:
services:
traefik:
image: traefik:3.5
command:
- "--api.insecure=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--providers.file.filename=etc/traefik/dynamic.yml"
ports:
- "80:80"
- "443:443"
- "8080:8080"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./traefik/certs:/etc/traefik/certs
- ./traefik/traefik.yml:/etc/traefik.yml:ro
- ./traefik/dynamic.yml:/etc/traefik/dynamic.yml:ro
networks:
- cpad-dev
networks:
cpad-dev:
external: true
For production, you’ll want a slightly different version of that config so create a separate docker-compose.prod.yml
file:
services:
traefik:
command:
- "--api.insecure=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--providers.file.filename=etc/traefik/dynamic.yml"
- "--certificatesresolvers.myresolver.acme.tlschallenge=true"
- "--certificatesresolvers.myresolver.acme.email=sajad@hey.com"
- "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./traefik/certs:/etc/traefik/certs
- ./traefik/traefik.yml:/etc/traefik.yml:ro
- ./traefik/dynamic.yml:/etc/traefik/dynamic.yml:ro
- letsencrypt:/letsencrypt
volumes:
letsencrypt:
When starting Docker Compose in production, run the below to ensure your production config is used:
docker compose up -f docker-compose.prod.yml -d
The main difference between the dev and production configs is the below:

You can read the docs here to better understand what those labels do.
Configure the application to use your resolver
In the Docker Compose file for your production application service, you’ll want something like this:
services:
php:
labels:
- traefik.enable=true
- traefik.http.routers.cpad-api.entrypoints=web
- traefik.http.routers.cpad-api.entrypoints=websecure
- traefik.http.routers.cpad-api.tls=true
- traefik.http.routers.cpad-api.rule=HOST(`api.cpad.app`)
- traefik.http.routers.cpad-api.middlewares=redirect-to-https
- traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https
- traefik.http.services.cpad-api.loadbalancer.server.port=8080
- traefik.http.routers.cpad-api.tls.certresolver=myresolver
The key Traefik label to enable HTTPs via Traefik is that last line:
- traefik.http.routers.cpad-api.tls.certresolver=myresolver