Setting Up Traefik as a Reverse Proxy for Docker Containers
I've been running Traefik in my homelab for nearly two years now, and I honestly can't imagine managing multiple Docker services without it. If you're tired of manually mapping ports, juggling SSL certificates, and manually configuring Nginx for each new service, Traefik is a game-changer. It automatically discovers your Docker containers, provisions Let's Encrypt certificates, and handles routing—all through a single configuration file.
In this guide, I'll walk you through deploying Traefik with Docker Compose, configuring automatic SSL/TLS termination, and routing traffic to multiple backend services. By the end, you'll have a production-ready reverse proxy that scales with your homelab.
Why Traefik Over Nginx or Caddy?
Don't get me wrong—Nginx and Caddy are excellent. But Traefik was built for container orchestration from the ground up. Here's what sold me:
- Automatic service discovery: Traefik reads Docker labels and automatically registers new containers without reloading the proxy.
- Native Let's Encrypt integration: SSL certificates are provisioned and renewed automatically—no external scripts needed.
- Middleware support: Rate limiting, authentication, compression, and request logging are all built in.
- Dashboard: A web UI to visualize all your routes, services, and certificate status in real time.
Caddy does auto-HTTPS beautifully, but it's less container-aware. Nginx is rock-solid but requires manual config updates and certificate renewal scripts. Traefik just works with Docker.
Prerequisites and Architecture
You'll need:
- A VPS or homelab machine running Ubuntu 22.04+ (or your preferred Linux distro)
- Docker and Docker Compose installed
- A domain name pointing to your server's IP address
- Port 80 and 443 exposed on your firewall (Traefik listens on these)
If you don't have a VPS yet, I'd recommend checking RackNerd. They offer reliable KVM instances for around $40 per year—more than adequate for running Traefik and several backend services.
Docker Compose Configuration
Here's the core Traefik setup I use. This configuration includes the Traefik container itself, automatic Let's Encrypt provisioning, and a dashboard.
version: '3.8'
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
- ./acme.json:/acme.json
- ./config.yml:/config.yml:ro
environment:
- TRAEFIK_API_DASHBOARD=true
- TRAEFIK_PROVIDERS_DOCKER=true
- TRAEFIK_PROVIDERS_DOCKER_EXPOSEDBYDEFAULT=false
networks:
- traefik
labels:
- "traefik.enable=true"
- "traefik.http.routers.dashboard.rule=Host(\`traefik.yourdomain.com\`)"
- "traefik.http.routers.dashboard.entrypoints=websecure"
- "traefik.http.routers.dashboard.tls.certresolver=letsencrypt"
- "traefik.http.routers.dashboard.service=api@internal"
- "traefik.http.routers.dashboard.middlewares=dashboard-auth"
- "traefik.http.middlewares.dashboard-auth.basicauth.users=admin:$$2y$$05$$HASHED_PASSWORD_HERE"
whoami:
image: traefik/whoami:latest
container_name: whoami
restart: always
networks:
- traefik
labels:
- "traefik.enable=true"
- "traefik.http.routers.whoami.rule=Host(\`whoami.yourdomain.com\`)"
- "traefik.http.routers.whoami.entrypoints=websecure"
- "traefik.http.routers.whoami.tls.certresolver=letsencrypt"
- "traefik.http.services.whoami.loadbalancer.server.port=80"
networks:
traefik:
driver: bridge
This compose file sets up Traefik with two containers: Traefik itself (with dashboard), and a simple test service called "whoami". The key points:
/var/run/docker.sockis mounted so Traefik can discover other containers.- Labels on each service tell Traefik how to route traffic to them.
acme.jsonstores your Let's Encrypt certificates (Traefik auto-renews them).- The dashboard is protected with HTTP Basic Auth.
Static Configuration File (traefik.yml)
Create a traefik.yml file in the same directory as your compose file:
api:
dashboard: true
debug: true
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
scheme: https
websecure:
address: ":443"
providers:
docker:
endpoint: unix:///var/run/docker.sock
exposedByDefault: false
network: traefik
file:
filename: /config.yml
watch: true
certificatesResolvers:
letsencrypt:
acme:
email: [email protected]
storage: /acme.json
httpChallenge:
entryPoint: web
log:
level: INFO
filePath: /var/log/traefik/access.log
accessLog:
filePath: /var/log/traefik/access.log
Here's what each section does:
entryPoints: Defines where Traefik listens (HTTP on 80, HTTPS on 443).providers: Tells Traefik to read container labels and watch the config file for changes.certificatesResolvers: Configures Let's Encrypt with HTTP challenge (easiest for most setups).log: Sets logging level and file paths.
acme.json file must be readable only by Traefik (permissions 600). If permissions are wrong, Let's Encrypt won't work. After creating it, run: chmod 600 acme.json
Generating Your BasicAuth Password
For the dashboard, I use HTTP Basic Auth. To generate a bcrypt-hashed password, run:
apt-get install apache2-utils
htpasswd -nB admin
This will prompt you for a password and output a line like admin:$2y$05$.... Replace the value in the docker-compose labels. In YAML, you need to escape the dollar signs, so $ becomes $$.
Starting Traefik
Create the necessary directories and files, then start the stack:
mkdir -p traefik-setup
cd traefik-setup
touch acme.json
chmod 600 acme.json
# Copy the compose and config files here, edit them with your domain
docker-compose up -d
# Check logs
docker-compose logs -f traefik
Within a few seconds, you should see Traefik starting and listening on ports 80 and 443. Visit https://traefik.yourdomain.com (replace with your domain) and log in with your basicauth credentials. You'll see the dashboard showing the test "whoami" service.
Adding More Services
To add any new Docker service to Traefik, just add labels. Here's an example with Nextcloud:
nextcloud:
image: nextcloud:latest
container_name: nextcloud
restart: always
networks:
- traefik
environment:
- NEXTCLOUD_TRUSTED_DOMAINS=nextcloud.yourdomain.com
volumes:
- ./nextcloud:/var/www/html
labels:
- "traefik.enable=true"
- "traefik.http.routers.nextcloud.rule=Host(\`nextcloud.yourdomain.com\`)"
- "traefik.http.routers.nextcloud.entrypoints=websecure"
- "traefik.http.routers.nextcloud.tls.certresolver=letsencrypt"
- "traefik.http.services.nextcloud.loadbalancer.server.port=80"
Add this to your compose file (in the services section), then run docker-compose up -d. Traefik automatically discovers it, provisions a certificate, and routes nextcloud.yourdomain.com to your container. No manual proxy configuration needed.
Middleware: Rate Limiting and Compression
Traefik supports middleware for advanced routing. Here's a static config (config.yml) that adds rate limiting and compression:
http:
middlewares:
ratelimit:
rateLimit:
average: 100
period: 1m
burst: 20
compression:
compress:
minLength: 1024
security-headers:
headers:
frameDeny: true
browserXssFilter: true
contentTypeNosniff: true
sslRedirect: true
sslHost: yourdomain.com
sslForceHost: true
routers:
nextcloud:
rule: Host(\`nextcloud.yourdomain.com\`)
entrypoints:
- websecure
middlewares:
- compression
- security-headers
tls:
certResolver: letsencrypt
Then apply these in your service labels:
- "traefik.http.routers.nextcloud.middlewares=ratelimit,compression,security-headers"
Monitoring and Troubleshooting
Traefik logs are verbose and helpful. Check them with:
docker-compose logs -f traefik | grep -i error
Common issues:
- Certificate stuck in pending: Check DNS resolution and firewall port 80 access.
- Backend service unreachable: Verify the service is on the correct Docker network and the port is correct.
- Dashboard won't load: Check basicauth credentials and ensure
traefik.yourdomain.comDNS is configured.
The dashboard shows real-time metrics and any routing errors. It's invaluable for debugging.
Next Steps
Now that you have Traefik running, consider:
- Adding Authelia for centralized authentication across all services.
- Deploying Uptime Kuma for service monitoring and status pages.
- Setting up Vaultwarden for password management—it integrates seamlessly with Traefik.
- Exploring Traefik's official documentation for advanced features like canary deployments and circuit breakers.
Traefik removes so much operational overhead once it's running. Future you will thank you for setting this up properly now.
Discussion