Traefik + Docker: Zero-Config Reverse Proxy That Discovers Your Containers Automatically
Traefik + Docker: Zero-Config Reverse Proxy That Discovers Your Containers Automatically
TL;DR: Traefik watches the Docker socket, auto-discovers new containers, and routes traffic to them based on labels. No config files to edit. No reloads. Just docker compose up and go.
The Nginx Problem
Every time you deploy a new microservice with Nginx, you:
- Write an upstream block in
nginx.conf - Add a
serverblock withproxy_pass - Run
nginx -tto test - Run
nginx -s reloadto apply - Set up Certbot for SSL
- Add a cron job for cert renewal
Multiply this by 10 services and you have 10 config blocks to maintain. Miss one reload and traffic breaks.
Traefik eliminates steps 1-6 entirely.
How Traefik Discovers Docker Containers
Traefik connects to the Docker socket (/var/run/docker.sock) and watches for container events:
Container started → Traefik reads labels → Creates route → Provisions SSL
Container stopped → Traefik removes route → Done
Container scaled → Traefik adds instances to load balancer → Done
No config files. No reloads. No human intervention.
Minimal Setup: 3 Files, 5 Minutes
File 1: traefik.yml
# Static configuration
api:
dashboard: true
insecure: true
entryPoints:
web:
address: ":80"
websecure:
address: ":443"
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
certificatesResolvers:
letsencrypt:
acme:
email: you@example.com
storage: /acme.json
httpChallenge:
entryPoint: web
File 2: docker-compose.yml
version: '3.8'
services:
traefik:
image: traefik:v3.1
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "8080:8080"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik.yml:/traefik.yml:ro
- ./acme.json:/acme.json
networks:
- web
networks:
web:
name: web
File 3: Prepare SSL storage
touch acme.json && chmod 600 acme.json
docker compose up -d
Done. Traefik is running. Dashboard at http://localhost:8080.
Adding Services: Just Labels
Here’s where Traefik shines. To add a new service, you don’t touch Traefik at all. You just add labels to your service’s Docker Compose:
Example: FastAPI Application
# app/docker-compose.yml
version: '3.8'
services:
fastapi:
build: .
restart: unless-stopped
labels:
- "traefik.enable=true"
- "traefik.http.routers.fastapi.rule=Host(`api.mysite.com`)"
- "traefik.http.routers.fastapi.entrypoints=websecure"
- "traefik.http.routers.fastapi.tls.certresolver=letsencrypt"
- "traefik.http.services.fastapi.loadbalancer.server.port=8000"
networks:
- web
networks:
web:
external: true
docker compose up -d
# Traefik automatically:
# 1. Detects the container
# 2. Creates route for api.mysite.com
# 3. Requests SSL certificate from Let's Encrypt
# 4. Starts routing HTTPS traffic
Example: WordPress
services:
wordpress:
image: wordpress:6
restart: unless-stopped
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: wp
WORDPRESS_DB_PASSWORD: secret
WORDPRESS_DB_NAME: wordpress
labels:
- "traefik.enable=true"
- "traefik.http.routers.wordpress.rule=Host(`blog.mysite.com`)"
- "traefik.http.routers.wordpress.entrypoints=websecure"
- "traefik.http.routers.wordpress.tls.certresolver=letsencrypt"
- "traefik.http.services.wordpress.loadbalancer.server.port=80"
networks:
- web
- backend
db:
image: mariadb:11
environment:
MYSQL_DATABASE: wordpress
MYSQL_USER: wp
MYSQL_PASSWORD: secret
MYSQL_ROOT_PASSWORD: rootsecret
volumes:
- db_data:/var/lib/mysql
networks:
- backend
volumes:
db_data:
networks:
web:
external: true
backend:
Example: Multiple Services in One Compose
services:
frontend:
image: node:20-alpine
command: npx serve -s build -l 3000
labels:
- "traefik.enable=true"
- "traefik.http.routers.frontend.rule=Host(`mysite.com`)"
- "traefik.http.routers.frontend.entrypoints=websecure"
- "traefik.http.routers.frontend.tls.certresolver=letsencrypt"
- "traefik.http.services.frontend.loadbalancer.server.port=3000"
networks:
- web
api:
build: ./api
labels:
- "traefik.enable=true"
- "traefik.http.routers.api.rule=Host(`mysite.com`) && PathPrefix(`/api`)"
- "traefik.http.routers.api.entrypoints=websecure"
- "traefik.http.routers.api.tls.certresolver=letsencrypt"
- "traefik.http.services.api.loadbalancer.server.port=8000"
# Strip /api prefix before forwarding
- "traefik.http.middlewares.api-strip.stripprefix.prefixes=/api"
- "traefik.http.routers.api.middlewares=api-strip"
networks:
- web
adminer:
image: adminer
labels:
- "traefik.enable=true"
- "traefik.http.routers.adminer.rule=Host(`db.mysite.com`)"
- "traefik.http.routers.adminer.entrypoints=websecure"
- "traefik.http.routers.adminer.tls.certresolver=letsencrypt"
- "traefik.http.services.adminer.loadbalancer.server.port=8080"
# Protect with basic auth
- "traefik.http.middlewares.admin-auth.basicauth.users=admin:$$apr1$$xyz$$hash"
- "traefik.http.routers.adminer.middlewares=admin-auth"
networks:
- web
networks:
web:
external: true
Scaling Services
# Scale API to 5 instances
docker compose up -d --scale api=5
# Traefik automatically load-balances across all 5
Check in dashboard (http://localhost:8080) — you’ll see 5 server entries under the API service.
HTTP to HTTPS Redirect
Add global redirect in traefik.yml:
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
scheme: https
permanent: true
websecure:
address: ":443"
All HTTP traffic automatically redirects to HTTPS. Every service. No per-service config.
Useful Docker Labels Reference
labels:
# Basic routing
- "traefik.enable=true"
- "traefik.http.routers.NAME.rule=Host(`domain.com`)"
- "traefik.http.routers.NAME.entrypoints=websecure"
- "traefik.http.routers.NAME.tls.certresolver=letsencrypt"
- "traefik.http.services.NAME.loadbalancer.server.port=PORT"
# Path routing
- "traefik.http.routers.NAME.rule=Host(`domain.com`) && PathPrefix(`/api`)"
# Strip prefix
- "traefik.http.middlewares.strip.stripprefix.prefixes=/api"
- "traefik.http.routers.NAME.middlewares=strip"
# Basic auth
- "traefik.http.middlewares.auth.basicauth.users=user:hash"
- "traefik.http.routers.NAME.middlewares=auth"
# Rate limiting
- "traefik.http.middlewares.rate.ratelimit.average=100"
- "traefik.http.middlewares.rate.ratelimit.burst=50"
# Health check
- "traefik.http.services.NAME.loadbalancer.healthcheck.path=/health"
- "traefik.http.services.NAME.loadbalancer.healthcheck.interval=10s"
# Sticky sessions
- "traefik.http.services.NAME.loadbalancer.sticky.cookie=true"
# Custom headers
- "traefik.http.middlewares.headers.headers.customResponseHeaders.X-Custom=value"
# Compression
- "traefik.http.middlewares.gzip.compress=true"
Debugging
# Check Traefik logs
docker logs traefik -f --tail 50
# Verify container labels
docker inspect <container_id> | jq '.[0].Config.Labels'
# Test routing
curl -H "Host: api.mysite.com" http://localhost
# Check certificate status
curl -vI https://api.mysite.com 2>&1 | grep -A5 "Server certificate"
Summary
Traefik + Docker = reverse proxy that configures itself:
- Run Traefik once with Docker socket access
- Add labels to any new service
docker compose up -d— traffic routes automatically, SSL provisions automatically- Scale with
--scale— load balancing is automatic - No config files to edit. No reloads. No Certbot cron jobs.
One Traefik instance handles all your services. Forever.
Need a custom automation or scraping tool? 79+ production actors on Apify Store. Questions or custom work? Email spinov001@gmail.com
More tips on web scraping, APIs, and Python: https://t.me/scraping_ai