Traefik: Reverse Proxy for Docker with Automatic SSL
Configure Traefik as reverse proxy for your Docker containers. Automatic Let's Encrypt SSL, dynamic routing and integrated dashboard.
Traefik is a modern reverse proxy designed for Docker. Unlike Nginx, it automatically detects launched containers and exposes them without modifying the configuration: just add labels to the container.
File structure
traefik/
├── docker-compose.yml
├── traefik.yml # static configuration
└── data/
├── acme.json # Let's Encrypt certificates (create empty)
└── traefik.logmkdir -p traefik/data
touch traefik/data/acme.json
chmod 600 traefik/data/acme.json # REQUIREDStatic configuration (traefik.yml)
# traefik/traefik.yml
api:
dashboard: true
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
scheme: https
websecure:
address: ":443"
certificatesResolvers:
letsencrypt:
acme:
email: admin@yourdomain.com
storage: /data/acme.json
httpChallenge:
entryPoint: web
providers:
docker:
exposedByDefault: false # containers must explicitly opt-in
file:
filename: /traefik.yml
log:
filePath: /data/traefik.log
level: INFOdocker-compose.yml for Traefik
# traefik/docker-compose.yml
services:
traefik:
image: traefik:v3.0
container_name: traefik
restart: always
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik.yml:/traefik.yml:ro
- ./data:/data
networks:
- traefik_net
labels:
- "traefik.enable=true"
# Dashboard (protect with authentication in production)
- "traefik.http.routers.dashboard.rule=Host(`traefik.yourdomain.com`)"
- "traefik.http.routers.dashboard.service=api@internal"
- "traefik.http.routers.dashboard.tls.certresolver=letsencrypt"
networks:
traefik_net:
external: true# Create the shared network
docker network create traefik_net
# Start Traefik
docker compose up -dExpose an application with Traefik
Add labels to your app container: Traefik reads them automatically:
# app/docker-compose.yml
services:
myapp:
image: nginx:alpine
networks:
- traefik_net
labels:
- "traefik.enable=true"
- "traefik.http.routers.myapp.rule=Host(`app.yourdomain.com`)"
- "traefik.http.routers.myapp.tls.certresolver=letsencrypt"
- "traefik.http.services.myapp.loadbalancer.server.port=80"
networks:
traefik_net:
external: trueSSL is automatically issued from Let's Encrypt on first access.
Practical examples
WordPress + MySQL
services:
wordpress:
image: wordpress:latest
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_NAME: wp
WORDPRESS_DB_USER: wpuser
WORDPRESS_DB_PASSWORD: password
networks:
- traefik_net
- internal
labels:
- "traefik.enable=true"
- "traefik.http.routers.wp.rule=Host(`blog.yourdomain.com`)"
- "traefik.http.routers.wp.tls.certresolver=letsencrypt"
- "traefik.http.services.wp.loadbalancer.server.port=80"
db:
image: mariadb:11
environment:
MARIADB_DATABASE: wp
MARIADB_USER: wpuser
MARIADB_PASSWORD: password
MARIADB_ROOT_PASSWORD: rootpassword
volumes:
- db_data:/var/lib/mysql
networks:
- internal
networks:
traefik_net:
external: true
internal:
volumes:
db_data:Protection with HTTP basic authentication
# Generate password (htpasswd)
apt install apache2-utils -y
htpasswd -nb admin YourPassword
# Output: admin:$apr1$...labels:
- "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$..."
- "traefik.http.routers.myapp.middlewares=auth"Double $$ in labels
In docker-compose.yml files, $ in htpasswd passwords must be doubled ($$) to prevent Docker from interpreting them as variables.
Certificate renewal
Traefik automatically renews Let's Encrypt certificates before expiration. No manual action needed.
To force renewal:
docker stop traefik
rm traefik/data/acme.json
touch traefik/data/acme.json && chmod 600 traefik/data/acme.json
docker start traefikPortainer: Docker Management via Web
Install Portainer to manage Docker containers, stacks, volumes and networks via web interface. No more CLI for daily operations.
Coolify: Self-hosted Heroku / Vercel
Install Coolify to deploy Node.js, PHP, Python, Docker and static site applications directly from Git with automatic SSL. Free alternative to Heroku and Vercel.