51.9 Traefik: route many sites by labels with automatic HTTPS (Let's Encrypt)
Friends, this is the last lesson of the networking chapter. One server, many websites, one port 443. Today Traefik reads container labels, sends each domain to the right container, and gets free HTTPS certificates by itself.
मित्रांनो, हा networking chapter चा शेवटचा lesson. एक server, अनेक websites, एकच port 443. आज Traefik container चे labels वाचून प्रत्येक domain योग्य container कडे पाठवतो, आणि free HTTPS certificates स्वतः घेतो.
दोस्तों, यह networking chapter का आख़िरी lesson है. एक server, कई websites, एक ही port 443. आज Traefik container के labels पढ़कर हर domain को सही container तक भेजता है, और free HTTPS certificates खुद लेता है.
1. Start from a story
Rohit runs a small agency in Nagpur. He hosts websites for a bakery, a dentist and a coaching class, all on one cheap server.
Only one program can listen on port 443. So who decides that bakery.example.com goes to the bakery container and dentist.example.com goes to the dentist container? Earlier Rohit edited an nginx file by hand for every new client and renewed certificates by hand every three months. Twice he forgot, and a client's site showed a red warning.
Then he moved to Traefik. Traefik watches Docker. When a new container starts with the right labels, Traefik adds a route at once, and asks Let's Encrypt for a certificate. No config file to edit, no reload, no forgotten renewals.
In this lesson we build Rohit's setup: Traefik in front, two sites behind it, labels for routing, a redirect from HTTP to HTTPS, and automatic certificates. We use example.com names; on your own server use your real domains.
2. Start Traefik
Step 1: A shared network for the proxy
Why: Traefik and the sites must share a network.
What: We create one external network named proxy and attach every site to it.
Example 1: Create
Type this:
docker network create proxy
You will see:
e7f1a2...
What it means: Shared by all stacks.
Example 2: Check
Type this:
docker network ls --filter name=proxy --format '{{.Name}} {{.Driver}}'
You will see:
proxy bridge
What it means: Ready.
Example 3: Why
Type this:
docker network inspect proxy -f '{{len .Containers}}'
You will see:
0
What it means: Empty now; sites join later.
Step 2: Run Traefik with the Docker provider
Why: Traefik learns about containers from the Docker socket.
What: Mount the socket read-only and turn off auto-exposing every container.
Example 4: Run
Type this:
docker run -d --name traefik --network proxy -p 80:80 -p 443:443 -v /var/run/docker.sock:/var/run/docker.sock:ro traefik:v3.1 --providers.docker=true --providers.docker.exposedbydefault=false --entrypoints.web.address=:80 --entrypoints.websecure.address=:443
You will see:
9a8b...
What it means: Traefik is the front door.
Example 5: Logs
Type this:
docker logs traefik 2>&1 | tail -1
You will see:
level=info msg="Starting provider *docker.Provider"
What it means: Watching Docker.
Example 6: Version
Type this:
docker exec traefik traefik version | head -1
You will see:
Version: 3.1.2
What it means: Running v3.
Step 3: The dashboard (local only)
Why: See routes while you learn.
What: Enable the API and publish it only on 127.0.0.1.
Example 7: Flag
Type this:
--api.dashboard=true --api.insecure=true and -p 127.0.0.1:8081:8080
You will see:
(added to the run line)
What it means: Never open this to the internet.
Example 8: Open
Type this:
curl -s 127.0.0.1:8081/api/http/routers | head -c 60
You will see:
[{"entryPoints":["web"],"service":"api@internal"
What it means: Routers listed as JSON.
Example 9: From outside
Type this:
curl -s -m3 http://SERVER_IP:8081
You will see:
curl: (28) Connection timed out
What it means: Correctly hidden.
3. Route by labels
Step 4: traefik.enable
Why: Opt in each container.
What: Because exposedbydefault is false, only labelled containers get routes.
Example 10: Plain container
Type this:
docker run -d --name hidden --network proxy traefik/whoami:v1.10
You will see:
3c4d...
What it means: No labels, no route.
Example 11: Check
Type this:
curl -s 127.0.0.1:8081/api/http/routers | grep -c hidden
You will see:
0
What it means: Not exposed.
Example 12: Opt in
Type this:
docker run -d --name bakery --network proxy -l traefik.enable=true traefik/whoami:v1.10
You will see:
5e6f...
What it means: Now Traefik sees it.
Step 5: Host rule
Why: Send a domain to a container.
What: The router rule matches the Host header of the request.
Example 13: Run with rule
Type this:
docker run -d --name bakery --network proxy -l traefik.enable=true -l 'traefik.http.routers.bakery.rule=Host(`bakery.example.com`)' -l traefik.http.routers.bakery.entrypoints=web traefik/whoami:v1.10
You will see:
7a8b...
What it means: Domain to container.
Example 14: Test
Type this:
curl -s -H 'Host: bakery.example.com' localhost | head -1
You will see:
Hostname: 7a8b9c0d1e2f
What it means: The bakery answered.
Example 15: Unknown host
Type this:
curl -s -o /dev/null -w '%{http_code}\n' -H 'Host: nobody.example.com' localhost
You will see:
404
What it means: No route, no site.
Step 6: Second site, zero config edits
Why: Adding a client is just starting a container.
What: Same labels, new name and new domain.
Example 16: Dentist
Type this:
docker run -d --name dentist --network proxy -l traefik.enable=true -l 'traefik.http.routers.dentist.rule=Host(`dentist.example.com`)' traefik/whoami:v1.10
You will see:
1f2e...
What it means: Live in a second.
Example 17: Test
Type this:
curl -s -H 'Host: dentist.example.com' localhost | head -1
You will see:
Hostname: 1f2e3d4c5b6a
What it means: Right site.
Example 18: Routers
Type this:
curl -s 127.0.0.1:8081/api/http/routers | grep -o '"name":"[a-z]*@docker'
You will see:
"name":"bakery@docker
"name":"dentist@docker
What it means: Both routes exist.
Step 7: Path rules and the service port
Why: More rules, and which port to use.
What: PathPrefix routes by URL path. loadbalancer.server.port tells Traefik the app port.
Example 19: Path
Type this:
-l 'traefik.http.routers.api.rule=Host(`coaching.example.com`) && PathPrefix(`/api`)'
You will see:
(label)
What it means: Only /api goes here.
Example 20: Port
Type this:
-l traefik.http.services.api.loadbalancer.server.port=3000
You will see:
(label)
What it means: The app listens on 3000.
Example 21: Test
Type this:
curl -s -o /dev/null -w '%{http_code}\n' -H 'Host: coaching.example.com' localhost/api/health
You will see:
200
What it means: Path route works.
4. Automatic HTTPS
Step 8: A certificate resolver
Why: Tell Traefik how to get certificates.
What: Use the HTTP challenge on port 80 and store certificates in a volume.
Example 22: Flags
Type this:
--certificatesresolvers.le.acme.email=admin@example.com --certificatesresolvers.le.acme.storage=/letsencrypt/acme.json --certificatesresolvers.le.acme.httpchallenge.entrypoint=web
You will see:
(added to the run line)
What it means: Use your own email.
Example 23: Volume
Type this:
-v traefik-certs:/letsencrypt
You will see:
(added to the run line)
What it means: Certificates survive restarts.
Example 24: File mode
Type this:
docker exec traefik ls -l /letsencrypt/acme.json
You will see:
-rw------- 1 root root 3412 acme.json
What it means: 600 permissions; Traefik insists.
Step 9: Use the resolver on a site
Why: Two labels turn on HTTPS.
What: Point the router to websecure and the le resolver.
Example 25: Labels
Type this:
-l traefik.http.routers.bakery.entrypoints=websecure -l traefik.http.routers.bakery.tls.certresolver=le
You will see:
(labels)
What it means: HTTPS for the bakery.
Example 26: Logs
Type this:
docker logs traefik 2>&1 | grep -i 'certificate obtained'
You will see:
level=info msg="Certificate obtained for domains [bakery.example.com]"
What it means: Issued in seconds.
Example 27: Check
Type this:
curl -sI https://bakery.example.com | head -1
You will see:
HTTP/2 200
What it means: Green lock in the browser.
Step 10: Redirect HTTP to HTTPS
Why: Never serve the plain site.
What: One entrypoint setting redirects every site.
Example 28: Flags
Type this:
--entrypoints.web.http.redirections.entrypoint.to=websecure --entrypoints.web.http.redirections.entrypoint.scheme=https
You will see:
(added to the run line)
What it means: Global redirect.
Example 29: Test
Type this:
curl -sI http://bakery.example.com | head -2
You will see:
HTTP/1.1 308 Permanent Redirect
Location: https://bakery.example.com/
What it means: Sent to HTTPS.
Example 30: Staging first
Type this:
--certificatesresolvers.le.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory
You will see:
(for testing)
What it means: Avoids rate limits while learning.
Step 11: Everything in Compose
Why: Keep it in one file per site.
What: Traefik in its own stack, each site in its own stack, joined by the external proxy network.
Example 31: Site file
Type this:
printf 'services:\n web:\n image: nginx:1.27\n networks: [proxy]\n labels:\n - traefik.enable=true\n - traefik.http.routers.bakery.rule=Host(`bakery.example.com`)\n - traefik.http.routers.bakery.tls.certresolver=le\nnetworks:\n proxy:\n external: true\n' > compose.yaml
You will see:
(no output)
What it means: Labels live with the site.
Example 32: Up
Type this:
docker compose up -d
You will see:
Container bakery-web-1 Started
What it means: Route and certificate appear.
Example 33: Remove
Type this:
docker compose down
You will see:
Container bakery-web-1 Removed
What it means: Route disappears by itself.
Step 12: Middlewares
Why: Small add-ons that change requests on the way.
What: Labels can add basic auth, security headers or rate limits to a router.
Example 34: Rate limit
Type this:
-l traefik.http.middlewares.slow.ratelimit.average=20 -l traefik.http.routers.bakery.middlewares=slow
You will see:
(labels)
What it means: About 20 requests per second per client.
Example 35: Headers
Type this:
-l traefik.http.middlewares.sec.headers.stsSeconds=31536000
You will see:
(label)
What it means: Browsers remember to use HTTPS.
Example 36: Test
Type this:
for i in $(seq 40); do curl -s -o /dev/null -w '%{http_code}\n' https://bakery.example.com; done | sort | uniq -c
You will see:
22 200
18 429
What it means: Extra requests get 429 Too Many Requests.
Step 13: Troubleshooting Traefik
Why: Know the usual suspects.
What: Most problems are a missing network, a wrong port or DNS not pointing to the server.
Example 37: Wrong network
Type this:
docker inspect bakery -f '{{range $k,$v := .NetworkSettings.Networks}}{{$k}} {{end}}'
You will see:
bridge
What it means: Not on proxy; Traefik gives 504 Gateway Timeout.
Example 38: DNS
Type this:
dig +short bakery.example.com
You will see:
203.0.113.10
What it means: Must be this server for the challenge.
Example 39: Errors
Type this:
docker logs traefik 2>&1 | grep -i error | tail -1
You will see:
level=error msg="Unable to obtain ACME certificate" error="... timeout during connect"
What it means: Port 80 blocked in the security group.
5. Safety notes
The Docker socket gives full control of the host. Mount it read-only, never publish the dashboard to the internet, and for stricter setups put a socket proxy between Traefik and Docker.
Keep acme.json in a volume and back it up; losing it means asking for all certificates again, and Let's Encrypt has weekly limits. Practise against the staging server first, then switch to production.
Finally, keep Traefik itself updated and pin a version tag such as v3.1 instead of latest, so an upgrade happens when you choose, not on a random restart.
Check yourself
Q1. Which label makes Traefik route a container when exposedbydefault is false?
traefik.enable=true.
Q2. Which rule sends a domain to a container?
Host(`name`).
Q3. Why is port 80 needed for Let's Encrypt?
For the HTTP challenge.
Q4. What does a 504 from Traefik usually mean?
The container is not on the shared network.
Friends, Traefik is the smart receptionist: it reads the labels, sends each visitor to the right shop and keeps every lock fresh. Did you understand? Let us try it once more. The networking chapter is complete; in the next chapter we move to Docker Compose in depth.
मित्रांनो, Traefik म्हणजे हुशार receptionist: labels वाचतो, प्रत्येक पाहुण्याला योग्य दुकानात पाठवतो, आणि प्रत्येक कुलूप ताजं ठेवतो. समजलं का? चला, पुन्हा एकदा करून पाहू. Networking चा chapter संपला; पुढच्या chapter मध्ये Docker Compose सविस्तर बघू.
दोस्तों, Traefik मतलब होशियार receptionist: labels पढ़ता है, हर मेहमान को सही दुकान भेजता है, और हर ताला ताज़ा रखता है. समझ आया? चलिए, एक बार फिर करके देखते हैं। Networking का chapter पूरा हुआ; अगले chapter में Docker Compose विस्तार से देखेंगे.
Ravindra Bagale's Tip
Always test with the Let's Encrypt staging server first. Switch to production only when the staging certificate works.
नेहमी आधी Let's Encrypt च्या staging server वर test करा. Staging certificate चालला की मगच production वर जा.
हमेशा पहले Let's Encrypt के staging server पर test कीजिए. Staging certificate चल जाए तभी production पर जाइए.
Lab: try at home
- Create the proxy network and start Traefik.
- Run two whoami sites with Host rules.
- Test both with curl -H Host.
- Open the dashboard on 127.0.0.1 only.
- Add the staging resolver and the HTTP to HTTPS redirect.
- Move one site into its own compose.yaml.
Recap
- Traefik routes by labels; no config file per site.
- exposedbydefault=false plus traefik.enable=true.
- Host and PathPrefix rules pick the container.
- certresolver gives automatic HTTPS.
- Port 80 must be open for the HTTP challenge.
- Mount the socket read-only and hide the dashboard.
Lab
- Publish nginx on 8080 and on 127.0.0.1 only.
- Connect API and MySQL by name on a user-defined bridge.
- Run a job with --network none.
- Debug a network with netshoot.
Practice task
Build a frontend network and an --internal backend network. Put nginx on both, the API on both and MySQL only on backend. Prove MySQL cannot reach the internet and nginx cannot be skipped.
Ravindra Bagale's Tip
First check that the app inside the container listens on 0.0.0.0. Listening on 127.0.0.1 is the mistake we find every day.
Container मध्ये app 0.0.0.0 वर listen करतंय का हे आधी तपासा. नेहमी 127.0.0.1 हीच चूक सापडते.
पहले जाँचिए कि container में app 0.0.0.0 पर listen कर रहा है या नहीं. रोज़ 127.0.0.1 वाली गलती ही मिलती है.
In short
- -p publishes; EXPOSE only documents.
- User-defined bridges give DNS by name.
- host shares the host stack; none has no network.
- Overlay spans Swarm hosts.
- macvlan puts containers on the real LAN.
- Debug with netshoot in the same namespace.
Revision card
Interview card