
How to Set Up Traefik with Docker for Effortless Container Routing
Modern microservices architectures demand a reverse proxy that can dynamically route traffic to containers as they spin up and down. Traefik, a cloud-native edge router, excels in this environment by integrating natively with Docker, eliminating the need for manual configuration files. This guide provides a detailed, step-by-step approach to setting up Traefik with Docker, ensuring automatic service discovery, TLS termination, and effortless container routing.
Understanding Traefik’s Core Concepts
Before diving into the setup, it is critical to grasp how Traefik operates. Unlike traditional reverse proxies (e.g., Nginx or HAproxy) that require static configuration reloads, Traefik uses providers to watch for changes in your infrastructure. The Docker provider, for instance, listens to the Docker daemon events. When a container starts or stops, Traefik updates its routing rules in real-time without a restart.
Key components include:
- EntryPoints: The network ports on which Traefik listens (e.g., HTTP on 80, HTTPS on 443).
- Routers: Define how to handle incoming requests, linking entry points to services based on rules (e.g., hostname
web.example.com). - Services: Backend containers receiving the routed traffic.
- Middlewares: Intermediaries that modify requests or responses (e.g., authentication, rate limiting).
Traefik automatically generates these components from Docker container labels, drastically reducing operational overhead.
Prerequisites and Environment Setup
To follow this guide, you need:
- A Linux server (Ubuntu 22.04 LTS recommended) with Docker Engine and Docker Compose installed.
- A registered domain name (e.g.,
example.com) with DNS A records pointing to your server’s public IP. - Ports 80 and 443 open on your firewall for HTTP and HTTPS traffic.
- Basic familiarity with the terminal and YAML syntax.
Verify Docker is installed:
docker --version
docker-compose --version
Step 1: Create a Shared Docker Network
Traefik needs to communicate with other containers. A dedicated network ensures that Traefik can route traffic to containers regardless of their individual Compose files. Create a network named web:
docker network create web
This network will be attached to all containers that Traefik should route to.
Step 2: Configure Traefik with Docker Compose
Create a directory for Traefik and a docker-compose.yml file:
mkdir ~/traefik
cd ~/traefik
nano docker-compose.yml
Insert the following configuration, which sets up Traefik with the Docker provider, HTTP/HTTPS entry points, and Let’s Encrypt for automatic TLS certificates:
version: '3.8'
services:
traefik:
image: traefik:v3.0
container_name: traefik
restart: unless-stopped
security_opt:
- no-new-privileges:true
networks:
- web
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik.yml:/traefik.yml:ro
- ./acme.json:/acme.json
labels:
- "traefik.enable=true"
- "traefik.http.routers.dashboard.rule=Host(`traefik.example.com`)"
- "traefik.http.routers.dashboard.service=api@internal"
- "traefik.http.routers.dashboard.middlewares=auth"
- "traefik.http.middlewares.auth.basicauth.users=admin:$$2y$$10$$YourHashedPasswordHere"
Replace traefik.example.com with your actual subdomain. The acme.json file will store Let’s Encrypt certificates. Create it with restricted permissions:
touch acme.json
chmod 600 acme.json
Step 3: Create the Static Configuration File
Traefik reads its static configuration from a file (or CLI arguments). Create traefik.yml in the same directory:
api:
dashboard: 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: web
certificatesResolvers:
letsencrypt:
acme:
email: your-email@example.com
storage: acme.json
httpChallenge:
entryPoint: web
Key points:
exposedByDefault: falseensures Traefik only routes to containers explicitly labeled for routing—a crucial security practice.- The HTTP entrypoint automatically redirects to HTTPS.
- Let’s Encrypt ACME resolver handles certificate issuance and renewal.
Replace the email with yours. For the dashboard authentication, generate a strong password hash using:
echo $(htpasswd -nb admin "your_strong_password") | sed -e s/\$/\$\$/g
Copy the output and paste it in the labels section of the Compose file.
Step 4: Deploy Traefik
Start the Traefik container:
docker-compose up -d
Check logs to ensure it’s running correctly:
docker-compose logs -f
You should see logs indicating that the Docker provider is watching for events and that entry points are initialized. Visit https://traefik.example.com (your actual subdomain) and log in with the admin credentials. The dashboard displays routers, services, and middlewares.
Step 5: Route Traffic to a Docker Container
Now, route traffic to a sample container, such as whoami, a lightweight HTTP service that returns request information. Create a new directory for the service:
mkdir ~/whoami
cd ~/whoami
nano docker-compose.yml
Add the following:
version: '3.8'
services:
whoami:
image: traefik/whoami
container_name: whoami
networks:
- web
labels:
- "traefik.enable=true"
- "traefik.http.routers.whoami.rule=Host(`whoami.example.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
Replace whoami.example.com with your actual subdomain. Notice traefik.http.services.whoami.loadbalancer.server.port=80 tells Traefik which port the container exposes internally.
Deploy the service:
docker-compose up -d
Within seconds, Traefik detects the new container and generates routing rules. Visit https://whoami.example.com—you should see a page displaying the request headers, proving that Traefik successfully routed traffic.
Step 6: Add TLS and Automatic Certificate Renewal
With the certresolver=letsencrypt label, Traefik automatically requests a certificate from Let’s Encrypt the first time the container is accessed. Verification is done via HTTP challenge on port 80 (the web entrypoint), which is redirected to HTTPS. Ensure DNS resolves correctly; otherwise, certificate issuance fails.
Check certificate status in the Traefik dashboard under “ACME” or inspect the acme.json file:
cat acme.json | jq '.'
This JSON file stores certificates and keys. Traefik handles renewal 30 days before expiration automatically, with no intervention needed.
Step 7: Fine-Tune Routing with Middlewares
Middlewares add power to Traefik. For example, to add rate limiting to protect an API, modify the whoami container labels:
labels:
- "traefik.http.routers.whoami.middlewares=ratelimit"
- "traefik.http.middlewares.ratelimit.ratelimit.average=100"
- "traefik.http.middlewares.ratelimit.ratelimit.burst=50"
Or, to add HTTP Basic Auth for a staging environment:
labels:
- "traefik.http.routers.whoami.middlewares=staging-auth"
- "traefik.http.middlewares.staging-auth.basicauth.users=testuser:$$2y$$10$$HashedPassword"
Middlewares are reusable across routers and can be chained, e.g., middlewares=auth,ratelimit,retry.
Step 8: Handle Multiple Containers with Path Prefixes
For services sharing a domain, use path-based routing. Suppose you have an API and a frontend under app.example.com. Label the API container:
- "traefik.http.routers.api.rule=Host(`app.example.com`) && PathPrefix(`/api`)"
And the frontend:
- "traefik.http.routers.frontend.rule=Host(`app.example.com`) && PathPrefix(`/`)"
Traefik evaluates rules by specificity; more specific rules (e.g., with PathPrefix) are prioritized. Additionally, you can use the PathStrip middleware to remove the prefix before forwarding to the container:
- "traefik.http.middlewares.strip-api.stripprefix.prefixes=/api"
- "traefik.http.routers.api.middlewares=strip-api"
Step 9: Enable Load Balancing and Sticky Sessions
Traefik supports load balancing across multiple replicas of a service. For example, run three whoami instances by scaling:
docker-compose up -d --scale whoami=3
Traefik automatically discovers the replicas and distributes requests. For sticky sessions (e.g., for stateful applications), add the cookie middleware:
- "traefik.http.services.whoami.loadbalancer.sticky.cookie.name=serversession"
Do not use sticky sessions without necessity, as they reduce failure tolerance.
Step 10: Monitor and Debug Traefik
The dashboard is your primary monitoring tool. Alternatively, enable access logs in traefik.yml:
accessLog: {}
Logs are sent to stdout by default. View them with:
docker-compose logs -f traefik
For more granular verbose logging, add:
log:
level: DEBUG
Use this only during troubleshooting, as it generates high volume.
Optimizing Security and Performance
- Docker Socket Restriction: Mount the Docker socket as read-only (
:ro) to prevent container breakout. - Network Isolation: Use separate networks for internal and external traffic. Place Traefik on the
webnetwork and backend containers on private networks, exposing only through Traefik. - Rate Limiting and IP Whitelisting: Protect sensitive endpoints with middleware. For example, restrict dashboard access by IP:
- "traefik.http.middlewares.dashboard-whitelist.ipwhitelist.sourcerange=192.168.1.0/24" - Disable Dashboard in Production: Remove the dashboard labels or restrict it to localhost.
Troubleshooting Common Issues
- Certificate Errors on First Request: DNS propagation delay can cause Let’s Encrypt to fail. Wait 5-10 minutes after updating DNS, then manually trigger a renewal by restarting Traefik:
docker-compose restart traefik. - Container Not Reachable: Verify the container is attached to the
webnetwork and labels are correctly spelled. Usedocker inspect container_name | grep traefikto check labels. - Port Conflicts: Ensure no other process uses ports 80 or 443. Stop any existing web server (e.g., Apache, Nginx) before starting Traefik.