Introduction: Why a Reverse Proxy?
In modern self-hosted environments, you’re often running multiple services — like a photo gallery (e.g., Immich), media server (e.g., Jellyfin), and dashboards. If all these services expose themselves directly on different ports, things quickly get messy. Enter the reverse proxy.
A reverse proxy routes incoming HTTP/HTTPS traffic to the right container based on domain or path. It allows you to:
- Use pretty domain names like
photos.example.com
- Enforce HTTPS with Let’s Encrypt
- Route requests internally by hostname instead of IP and port
- Apply access control, rate limits, or basic authentication centrally
And Traefik does all that, automatically, with minimal config.
🚀 Why Traefik Over Nginx?
While Nginx is popular and powerful, it’s static by default. Every new service requires you to edit config files and reload.
Traefik, on the other hand:
- Automatically discovers Docker containers
- Supports dynamic routing using Docker labels
- Comes with built-in Let’s Encrypt integration
- Has a web dashboard to visualize routes
- Requires minimal config
Traefik was designed for containerized environments from the start.
⚙️ How Traefik Works Internally
Traefik is composed of three key concepts:
1. EntryPoints
These define which ports Traefik listens on (e.g., :80
, :443
). You can think of these as your public gateways.
2. Routers
Routers match incoming requests (host, path, method) and forward them to services. They also define TLS settings and middleware.
3. Services
These are the actual Docker containers (or upstream backends) that respond to the requests.
4. Middlewares (Optional)
These are like plugins: things that transform requests (e.g., strip path, redirect HTTP to HTTPS, basic auth, etc).
📦 Installing Traefik with Docker Compose
Let’s build a fully functional Traefik setup using Docker Compose.
docker-compose.yml
version: '3.9'
services:
traefik:
image: traefik:v3.0
container_name: traefik
command:
- --api.dashboard=true
- --api.insecure=false
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
- --providers.docker=true
- --providers.docker.exposedbydefault=false
- --certificatesresolvers.cloudflare.acme.dnschallenge=true
- --certificatesresolvers.cloudflare.acme.dnschallenge.provider=cloudflare
- [email protected]
- --certificatesresolvers.cloudflare.acme.storage=/letsencrypt/acme.json
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./letsencrypt:/letsencrypt
environment:
- [email protected]
- CF_API_KEY=your_cloudflare_api_key
labels:
- "traefik.enable=true"
- "traefik.http.routers.traefik.rule=Host(`traefik.yourdomain.com`)"
- "traefik.http.routers.traefik.entrypoints=websecure"
- "traefik.http.routers.traefik.tls.certresolver=cloudflare"
- "traefik.http.routers.traefik.service=api@internal"
- "traefik.http.middlewares.traefik-auth.basicauth.users=admin:$$apr1$$6yLkU..."
- "traefik.http.routers.traefik.middlewares=traefik-auth"
You also need to create the directory ./letsencrypt
and touch acme.json
with permissions 600
.
mkdir letsencrypt
chmod 600 letsencrypt/acme.json
🔐 Securing the Dashboard
Never expose the dashboard to the public without auth. Use basic auth like above or restrict access to specific IPs.
Alternative example:
- "traefik.http.routers.traefik.middlewares=dashboard-auth"
- "traefik.http.middlewares.dashboard-auth.basicauth.usersfile=/users.htpasswd"
Generate passwords with:
htpasswd -nb admin strongpassword
🌍 Deploying a Sample Service Behind Traefik
services:
whoami:
image: traefik/whoami
container_name: whoami
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=cloudflare"
Start both containers:
docker compose up -d
Now visit https://whoami.yourdomain.com
— you’ll see the container response.
🔧 Additional Features to Explore
- Middleware: redirect, stripPrefix, basicAuth
- Rate-limiting
- Retry and load balancing
- Redirect HTTP to HTTPS automatically
- Wildcard TLS certificates
- Forward headers to preserve real IP
📘 Conclusion
Traefik makes deploying, securing, and managing multiple services in Docker easy and dynamic. With a few Docker labels and one compose file, you get:
- Auto-routing by domain
- HTTPS with Let’s Encrypt
- Centralized auth and middleware
- Visibility via dashboard
Traefik replaces hours of nginx tinkering with a declarative, scalable, and elegant solution.