Self-Host Traefik: The Ultimate Reverse Proxy for Your Homelab in 20 Minutes
Tired of manually configuring Nginx every time you add a service? Traefik auto-discovers your Docker containers and handles routing, SSL, and load balancing — zero config files required.
Why Traefik?
Traditional reverse proxies like Nginx or Apache require you to manually edit config files and reload services every time you add or change a backend. Traefik flips this model: it watches your Docker socket (or Kubernetes API, Consul, etc.) and automatically creates routes for containers with the right labels.
What you get:
- Auto-discovery: New containers get routes instantly via Docker labels
- Automatic HTTPS: Let's Encrypt integration with HTTP-01 or DNS-01 challenges
- Middleware: Built-in auth, rate limiting, headers, redirects, circuit breakers
- Dashboard: Real-time view of routers, services, and middlewares
- Lightweight: Single binary, ~30MB RAM, no external dependencies
Prerequisites
- A VPS or server with Docker + Docker Compose installed
- A domain pointed to your server (e.g.,
*.sysbrix.comA record) - Ports 80 and 443 open
- 5 minutes of actual work — the rest is copy-paste
Step 1: Create the Docker Network
Traefik needs a shared network to reach your containers:
docker network create web
Step 2: Docker Compose for Traefik
Create ~/traefik/docker-compose.yml:
version: "3.8"
services:
traefik:
image: traefik:v3.0
container_name: traefik
restart: unless-stopped
command:
# API and Dashboard
- "--api.dashboard=true"
- "--api.insecure=false"
# Docker provider
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--providers.docker.network=web"
# Entrypoints
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
# Redirect HTTP to HTTPS
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
# Let's Encrypt
- "[email protected]"
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
- "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
# Logging
- "--log.level=INFO"
- "--accesslog=true"
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./letsencrypt:/letsencrypt
networks:
- web
labels:
# Dashboard via traefik.sysbrix.com (optional, add auth!)
- "traefik.enable=true"
- "traefik.http.routers.dashboard.rule=Host(`traefik.sysbrix.com`)"
- "traefik.http.routers.dashboard.service=api@internal"
- "traefik.http.routers.dashboard.entrypoints=websecure"
- "traefik.http.routers.dashboard.tls.certresolver=letsencrypt"
# Basic auth for dashboard (user: admin, password: changeme)
- "traefik.http.routers.dashboard.middlewares=dashboard-auth"
- "traefik.http.middlewares.dashboard-auth.basicauth.users=admin:$$2y$$05$$rW0zZ6Y0Z0Z0Z0Z0Z0Z0Z0u3Z0Z0Z0Z0Z0Z0Z0Z0Z0Z0Z0Z0Z0Z0"
networks:
web:
external: true
Note: The basic auth hash above is a placeholder. Generate a real one with: htpasswd -nb admin yourpassword | sed -e s/\$/\$\$/g
Step 3: Start Traefik
cd ~/traefik
mkdir -p letsencrypt
chmod 600 letsencrypt
docker compose up -d
Step 4: Route a Container (The Magic Part)
Here's where Traefik shines. To expose any container, just add labels:
version: "3.8"
services:
whoami:
image: traefik/whoami
container_name: whoami
networks:
- web
labels:
- "traefik.enable=true"
- "traefik.http.routers.whoami.rule=Host(`whoami.sysbrix.com`)"
- "traefik.http.routers.whoami.entrypoints=websecure"
- "traefik.http.routers.whoami.tls.certresolver=letsencrypt"
- "traefik.http.services.whoami.loadbalancer.server.port=80"
networks:
web:
external: true
That's it. No Nginx reloads. No DNS juggling. Traefik sees the labels, gets the SSL cert, and routes traffic.
Step 5: Add Middleware (Auth, Headers, Rate Limit)
labels:
# ... router labels ...
# Rate limit: 100 requests per 10 seconds
- "traefik.http.middlewares.ratelimit.ratelimit.average=100"
- "traefik.http.middlewares.ratelimit.ratelimit.period=10s"
# Security headers
- "traefik.http.middlewares.secure-headers.headers.stsSeconds=31536000"
- "traefik.http.middlewares.secure-headers.headers.contentTypeNosniff=true"
- "traefik.http.middlewares.secure-headers.headers.frameDeny=true"
# Apply middlewares
- "traefik.http.routers.whoami.middlewares=ratelimit,secure-headers"
Verification
- Check Traefik is running:
docker logs traefik— look for "Configuration loaded" - Test HTTP redirect:
curl -I http://whoami.sysbrix.com→ should return 301 to HTTPS - Test HTTPS:
curl https://whoami.sysbrix.com→ valid cert + response - Dashboard: Visit
https://traefik.sysbrix.com(if enabled)
Real-World Example: Exposing Grafana
services:
grafana:
image: grafana/grafana:latest
networks: [web]
labels:
- "traefik.enable=true"
- "traefik.http.routers.grafana.rule=Host(`grafana.sysbrix.com`)"
- "traefik.http.routers.grafana.entrypoints=websecure"
- "traefik.http.routers.grafana.tls.certresolver=letsencrypt"
- "traefik.http.services.grafana.loadbalancer.server.port=3000"
Next Steps
- Wildcard certs: Switch to DNS-01 challenge for
*.sysbrix.comcerts - Authentik/Keycloak: Add forward-auth middleware for SSO across all services
- Fail2ban: Ban IPs at the Traefik level for extra security
- Metrics: Enable Prometheus metrics and visualize in Grafana
Traefik turns reverse proxy management from a chore into a non-event. Add a label, get HTTPS. That's the way it should have always worked.