Vous avez déployé. Les conteneurs sont sains. Les ports sont ouverts. Le DNS pointe correctement. Et pourtant Traefik renvoie un 404 calme et distant comme s’il vous rendait service.
Ce mode d’échec explique pourquoi certaines personnes appellent les reverse proxies « simples » : ils simplifient votre système en concentrant toutes vos erreurs en un seul endroit. Traefik + labels Docker est puissant, mais c’est aussi une arme à feu mal maniée. Il n’alertera pas toujours quand vos règles de routage ne correspondent pas. Il se contentera… de ne rien router.
Ce que signifie vraiment « échouer silencieusement » dans Traefik
« Échouer silencieusement » ne veut pas dire que Traefik est cassé. Cela signifie que Traefik fait exactement ce que vous lui avez dit—sur la base de labels que vous avez accidentellement fournis.
Symptômes typiques :
- Traefik renvoie
404 page not foundpour un hôte dont vous êtes sûr qu’il existe. - Vous atteignez l’entrypoint de Traefik, mais le router ne correspond jamais, donc il retombe sur le handler par défaut (404).
- Le conteneur est actif et à l’écoute, mais Traefik route vers le mauvais port interne (ou aucun).
- Les middlewares ne s’appliquent pas, TLS ne s’active pas, les redirections ne se produisent pas, et vous avez l’impression d’être hanté.
Traefik n’est pas « silencieux » si vous savez où regarder : le tableau de bord, la configuration du provider, l’affichage de la configuration dynamique et les logs. Le silence est sur votre terminal parce que les labels Docker sont faciles à taper de travers et difficiles à valider visuellement.
Faits intéressants et un peu de contexte
- Traefik a popularisé la « découverte de configuration » à l’ère des conteneurs : surveiller les événements Docker, construire des routes dynamiquement, éviter des configs proxy éditées à la main.
- Les labels Docker existaient avant l’ère Traefik ; ils étaient une fonctionnalité générique de métadonnées que les reverse proxies ont réutilisée comme plan de contrôle complet.
- Traefik v2 a changé le modèle mental : routers, services, middlewares ont remplacé le modèle frontend/backend plus simple de la v1. Beaucoup de configs « qui fonctionnaient l’an dernier » ont cessé de marcher ici.
- L’analyse des règles est devenue plus stricte : de petites erreurs de syntaxe dans
Host(), les guillemets ou les backticks empêchent souvent un router d’exister du tout. - Les EntryPoints ne sont pas des ports ; ce sont des écouteurs nommés. Un router lié à
websecurene correspondra pas au trafic arrivant surweb, même si les deux s’exécutent sur le même conteneur. - Les types YAML de Docker Compose font mal : un label qui ressemble à une chaîne peut être analysé d’une manière étrange à moins que vous ne le citiez.
- Les valeurs par défaut de Traefik peuvent masquer votre intention : si
exposedByDefaultest vrai, vous pouvez router accidentellement vers des conteneurs non étiquetés—jusqu’à ce que vous le désactiviez et que tout disparaisse. - Les expérimentations HTTP/3 ont changé les attentes : les piles d’edge récentes poussent QUIC ; des entrypoints et des réglages TLS mal alignés sont maintenant plus visibles parce que les clients réessaient différemment.
Cahier de diagnostics rapides (faites ceci dans l’ordre)
Si vous êtes d’astreinte et que chaque minute compte, arrêtez de deviner. Vérifiez le système de la façon dont Traefik le voit.
1) Est-ce que Traefik reçoit la requête sur l’entrypoint que vous croyez ?
- Confirmez que le client frappe la bonne IP/DNS.
- Confirmez que la requête atteint Traefik (et non une page d’état d’un LB cloud ou une ancienne IP).
- Confirmez HTTP vs HTTPS et le SNI de l’hôte.
2) Traefik a-t-il un router qui pourrait correspondre ?
- Vérifiez le tableau de bord ou l’API pour les routers.
- Cherchez le nom du router ; vérifiez la règle, les entrypoints, TLS et le binding du service.
3) Si le router existe, est-ce qu’il correspond ?
- Comparez exactement l’hôte/le chemin de la requête à la règle.
- Recherchez des conflits de priorité et des routers « catch-all ».
4) S’il correspond, Traefik peut-il atteindre le service ?
- Validez la connectivité réseau Docker : Traefik doit partager un réseau avec le conteneur cible.
- Vérifiez que le port utilisé par Traefik est correct : un port de load balancer explicite vaut mieux que la détection automatique.
5) S’il atteint le service, les middlewares et TLS font-ils ce que vous pensez ?
- Confirmez les noms de la chaîne de middlewares et le scope du provider (
@dockervs@file). - Vérifiez les réglages TLS :
tls=true,certresolver, domaines et entrypoint.
C’est l’ordre. Ne l’inversez pas. On perd la plupart du temps à déboguer des « certificats » alors que le router n’a jamais correspondu en premier lieu.
Comment Traefik décide où envoyer le trafic (et pourquoi les labels comptent)
Dans Traefik v2, le flux de la requête est :
- EntryPoint accepte la connexion (exemple :
websur :80,websecuresur :443). - Router correspond à la requête (règle : host/path/headers, plus entrypoints, plus exigence TLS).
- Middlewares mutent la requête/la réponse (redirection, auth, headers, rate-limit, etc.).
- Service définit l’upstream (IP:port du conteneur, options d’équilibrage).
Les labels Docker sont la source de configuration dynamique. Le provider Docker surveille les conteneurs et traduit les labels en routers/services/middlewares.
Voici l’essentiel : Traefik fonctionne volontiers avec une configuration partielle. Si votre label de router est mal formé, Traefik peut ne pas créer ce router du tout. Si votre router existe mais pointe vers un middleware inexistant, il peut échouer à l’attacher. Si le label de port du service manque et que Docker expose plusieurs ports, Traefik peut en choisir un mauvais.
Et si aucun router ne correspond, Traefik renvoie un 404 qui ressemble exactement à « Traefik est actif. » C’est pourquoi on perd des heures.
Une citation à retenir, parce que c’est tout le travail :
« L’espoir n’est pas une stratégie. » — Gene Kranz
Le débogage des labels Traefik est l’endroit où l’espoir vient mourir. Bien. Remplacez-le par l’observabilité et des conventions.
Corriger les labels correctement : modèles qui ne pourrissent pas
Principe 1 : Toujours nommer explicitement routers, services et middlewares
Se fier aux noms implicites conduit au « pourquoi Traefik attache-t-il le mauvais service ? » à 2 h du matin. Utilisez des noms stables. Utilisez-les partout.
Principe 2 : Toujours spécifier le port du service
Oui, Traefik peut détecter les ports automatiquement. Non, vous ne devriez pas le laisser faire, sauf si vous aimez le routage probabiliste.
Règle pratique : si un conteneur expose plusieurs ports, ou si vous utilisez des ports de health/admin, définissez toujours :
traefik.http.services.<service>.loadbalancer.server.port
Principe 3 : Un router par nom d’hôte + entrypoint, puis composer le comportement avec des middlewares
N’encombrez pas une seule règle de router avec trop de logique. Gardez les correspondances simples ; gardez le comportement modulaire.
Principe 4 : Citez les valeurs des labels dans Compose (et soyez cohérent avec les backticks)
Compose, c’est YAML. YAML a ses opinions. La syntaxe des règles Traefik a aussi ses opinions. Vous êtes pris entre deux parsers avec des définitions différentes de « chaîne ». Citez vos labels. Utilisez des backticks à l’intérieur des règles Traefik de manière cohérente.
Bon (entre guillemets): "Host(`app.example.com`) && PathPrefix(`/api`)"
Mauvais (non cité): Host(`app.example.com`) (parfois ça marche, jusqu’au jour où ça ne marche plus)
Principe 5 : Décidez si vous voulez exposer les conteneurs par défaut. Puis appliquez-le.
En production, définissez le provider Docker exposedByDefault=false et activez explicitement par service avec traefik.enable=true. Cela réduit les expositions accidentelles et rend aussi les échecs plus clairs : si ce n’est pas activé, cela n’apparaîtra pas.
Blague #1 : Si vous laissez exposedByDefault=true, vous ne gérez pas un reverse proxy — vous gérez un générateur de surprises.
Exemple canonique Compose qui évite les échecs silencieux
Ce modèle a moins de pièces mobiles et échoue plus bruyamment :
cr0x@server:~$ cat docker-compose.yml
version: "3.9"
networks:
edge:
external: true
services:
traefik:
image: traefik:v2.11
command:
- --api.dashboard=true
- --api.insecure=false
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
- --providers.docker=true
- --providers.docker.exposedbydefault=false
- --providers.docker.network=edge
- --log.level=INFO
- --accesslog=true
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- edge
labels:
- "traefik.enable=true"
- "traefik.http.routers.traefik.rule=Host(`traefik.example.com`)"
- "traefik.http.routers.traefik.entrypoints=websecure"
- "traefik.http.routers.traefik.tls=true"
- "traefik.http.routers.traefik.service=api@internal"
app:
image: ghcr.io/example/app:latest
environment:
- PORT=8080
networks:
- edge
labels:
- "traefik.enable=true"
- "traefik.http.routers.app.rule=Host(`app.example.com`)"
- "traefik.http.routers.app.entrypoints=websecure"
- "traefik.http.routers.app.tls=true"
- "traefik.http.routers.app.service=app-svc"
- "traefik.http.services.app-svc.loadbalancer.server.port=8080"
- "traefik.http.middlewares.app-headers.headers.framedeny=true"
- "traefik.http.routers.app.middlewares=app-headers"
Remarquez ce qui est explicite :
- Traefik utilise un réseau Docker spécifique (
--providers.docker.network=edge). - Le port du service app est fixé à 8080.
- Les noms de router/service/middleware sont stables et référencés explicitement.
- Traefik lui-même est routé via
api@internal, ce qui réduit la confusion du type « pourquoi le tableau de bord ne marche pas ? ».
Tâches pratiques : commandes, sorties et décisions (12+)
Voici les vérifications que j’exécute réellement. Chaque tâche inclut : la commande, la sortie typique, ce que cela signifie et la décision à prendre.
Task 1: Confirm Traefik container is running and which image/version
cr0x@server:~$ docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}'
NAMES IMAGE STATUS PORTS
traefik traefik:v2.11 Up 2 hours 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp
app ghcr.io/example/app:latest Up 2 hours
Signification : Traefik est en cours et lie :80/:443 sur l’hôte.
Décision : Si Traefik n’est pas actif ou si les ports ne sont pas mappés, arrêtez. Corrigez le cycle de vie du conteneur ou le pare-feu de l’hôte avant de toucher aux labels.
Task 2: Inspect Traefik startup flags (providers, exposedByDefault, network)
cr0x@server:~$ docker inspect traefik --format '{{json .Config.Cmd}}'
["--api.dashboard=true","--entrypoints.web.address=:80","--entrypoints.websecure.address=:443","--providers.docker=true","--providers.docker.exposedbydefault=false","--providers.docker.network=edge","--log.level=INFO","--accesslog=true"]
Signification : Le provider Docker est activé, l’exposition par défaut est désactivée, et Traefik cherchera les backends sur le réseau edge.
Décision : Si --providers.docker.network est défini, votre app doit être attachée à ce réseau ou le routage échouera.
Task 3: Verify the app container is on the same Docker network Traefik expects
cr0x@server:~$ docker inspect app --format '{{json .NetworkSettings.Networks}}'
{"edge":{"IPAMConfig":null,"Links":null,"Aliases":["app","3e9c1b7b4a2d"],"MacAddress":"02:42:ac:18:00:05","DriverOpts":null,"NetworkID":"b7b9d6c3b34a","EndpointID":"f2b59b5f8e67","Gateway":"172.24.0.1","IPAddress":"172.24.0.5","IPPrefixLen":16,"IPv6Gateway":"","GlobalIPv6Address":"","GlobalIPv6PrefixLen":0,"DNSNames":["app","3e9c1b7b4a2d"]}}
Signification : L’app est sur edge avec une IP que Traefik peut atteindre.
Décision : Si l’app n’est pas sur ce réseau, ajoutez-la. Ne « ouvrez » pas juste un port sauf si vous voulez contourner votre proxy entièrement.
Task 4: Confirm the labels Traefik will read (and spot typos fast)
cr0x@server:~$ docker inspect app --format '{{json .Config.Labels}}' | jq -r 'to_entries[] | "\(.key)=\(.value)"' | sort
traefik.enable=true
traefik.http.routers.app.entrypoints=websecure
traefik.http.routers.app.rule=Host(`app.example.com`)
traefik.http.routers.app.service=app-svc
traefik.http.routers.app.tls=true
traefik.http.routers.app.middlewares=app-headers
traefik.http.middlewares.app-headers.headers.framedeny=true
traefik.http.services.app-svc.loadbalancer.server.port=8080
Signification : Les labels sont présents et correctement orthographiés. Vous pouvez maintenant raisonner sur la configuration Traefik de manière déterministe.
Décision : Si vous voyez traefik.http.router (manque « s »), ou des noms décalés, corrigez les labels avant de toucher quoi que ce soit d’autre.
Task 5: Check Traefik logs for provider errors (parsing, missing middleware)
cr0x@server:~$ docker logs traefik --since 15m | tail -n 20
time="2026-01-03T09:18:41Z" level=info msg="Configuration loaded from flags."
time="2026-01-03T09:21:10Z" level=info msg="Skipping same configuration for provider docker"
time="2026-01-03T09:22:07Z" level=error msg="middleware \"app-auth@docker\" does not exist" routerName=app@docker entryPointName=websecure
time="2026-01-03T09:22:07Z" level=error msg="error while adding middleware: middleware \"app-auth@docker\" does not exist" entryPointName=websecure routerName=app@docker
Signification : Le router existe, mais référence un middleware qui n’existe pas. Cela route souvent encore, simplement sans le middleware, ce qui est une autre forme d’« échec silencieux ».
Décision : Définissez le label du middleware ou retirez-le du router. Ne laissez pas de références cassées traîner ; elles deviennent des failles de sécurité.
Task 6: Validate that routers exist by querying Traefik API (inside container)
cr0x@server:~$ docker exec -it traefik sh -lc 'wget -qO- http://127.0.0.1:8080/api/http/routers | head -n 20'
[{"entryPoints":["websecure"],"service":"app-svc@docker","rule":"Host(`app.example.com`)","status":"enabled","using":["websecure"],"name":"app@docker"},{"entryPoints":["websecure"],"service":"api@internal","rule":"Host(`traefik.example.com`)","status":"enabled","using":["websecure"],"name":"traefik@docker"}]
Signification : Votre router est réel dans la configuration dynamique de Traefik, pas seulement dans votre imagination.
Décision : Si votre router est absent ici, Traefik ne l’a pas chargé. C’est un problème de label, de contrainte provider ou de réglage d’exposition.
Task 7: Confirm the service port Traefik will use
cr0x@server:~$ docker exec -it traefik sh -lc 'wget -qO- http://127.0.0.1:8080/api/http/services | jq -r ".[] | select(.name==\"app-svc@docker\") | .loadBalancer.servers"'
[
{
"url": "http://172.24.0.5:8080"
}
]
Signification : Traefik pointe vers la bonne IP et le bon port.
Décision : Si vous voyez le mauvais port (souvent 80), définissez explicitement loadbalancer.server.port et redéployez.
Task 8: Test the backend directly from the Traefik container (network path check)
cr0x@server:~$ docker exec -it traefik sh -lc 'wget -qSO- http://172.24.0.5:8080/health -O /dev/null'
HTTP/1.1 200 OK
Content-Type: application/json
Date: Sat, 03 Jan 2026 09:25:01 GMT
Content-Length: 17
Signification : La connectivité est correcte ; les échecs sont dans le routage/la correspondance/TLS/middleware, pas dans la reachabilité réseau.
Décision : Si cela échoue, corrigez le réseau Docker, le port d’écoute du conteneur ou le binding de l’application (0.0.0.0 vs 127.0.0.1).
Task 9: Verify that the request Host header matches the router rule
cr0x@server:~$ curl -sS -D- -o /dev/null -H 'Host: app.example.com' http://127.0.0.1/
HTTP/1.1 301 Moved Permanently
Location: https://app.example.com/
Date: Sat, 03 Jan 2026 09:25:28 GMT
Content-Length: 17
Content-Type: text/plain; charset=utf-8
Signification : Quelque chose a correspondu sur HTTP et a probablement redirigé vers HTTPS (soit via un middleware, soit via une redirection d’entrypoint).
Décision : Si vous obtenez 404 ici, la règle du router n’a pas matché. Revérifiez les guillemets de la règle Host, le domaine et les entrypoints.
Task 10: Confirm HTTPS routing and certificate behavior (SNI matters)
cr0x@server:~$ curl -sS -D- -o /dev/null https://app.example.com/
HTTP/2 200
content-type: text/html; charset=utf-8
date: Sat, 03 Jan 2026 09:26:02 GMT
server: traefik
Signification : TLS fonctionne et le router matche sur websecure.
Décision : Si la poignée de main TLS échoue ou si vous voyez le mauvais certificat, vérifiez les flags TLS du router, le certresolver, et si vous touchez la bonne instance Traefik.
Task 11: Detect rule conflicts and priority issues
cr0x@server:~$ docker exec -it traefik sh -lc 'wget -qO- http://127.0.0.1:8080/api/http/routers | jq -r ".[] | [.name,.rule,(.priority|tostring)] | @tsv" | sort -k2'
app@docker Host(`app.example.com`)
catchall@docker HostRegexp(`{any:.+}`) 1
Signification : Vous avez un router catch-all qui peut capter le trafic si sa priorité est plus haute ou si votre router app ne correspond pas précisément.
Décision : Définissez des priorités explicites. Ne comptez pas sur « ça va s’ordonner tout seul ». Ce n’est pas le cas.
Task 12: Check Docker events to see if Traefik is even noticing container changes
cr0x@server:~$ docker events --since 5m --filter type=container --filter event=start
2026-01-03T09:24:10.128722391Z container start 3e9c1b7b4a2d (image=ghcr.io/example/app:latest, name=app)
Signification : Docker émet des événements de cycle de vie ; Traefik devrait les capter s’il a accès au socket.
Décision : Si Traefik ne se met pas à jour, confirmez que le montage du socket Docker est présent et que les permissions de lecture sont suffisantes.
Task 13: Confirm Traefik can read the Docker socket (common in hardened setups)
cr0x@server:~$ docker exec -it traefik sh -lc 'ls -l /var/run/docker.sock'
srw-rw---- 1 root docker 0 Jan 3 08:01 /var/run/docker.sock
Signification : Le socket existe. Les permissions peuvent encore poser problème selon l’utilisateur de Traefik.
Décision : Si Traefik tourne en non-root et ne peut pas lire ce socket, vous verrez des erreurs du provider et des routers manquants. Corrigez l’utilisateur/groupe ou exécutez avec les permissions appropriées.
Task 14: Validate the Compose file you actually deployed (not the one you edited)
cr0x@server:~$ docker compose config | sed -n '1,120p'
services:
app:
image: ghcr.io/example/app:latest
labels:
traefik.enable: "true"
traefik.http.routers.app.entrypoints: websecure
traefik.http.routers.app.rule: Host(`app.example.com`)
traefik.http.routers.app.service: app-svc
traefik.http.routers.app.tls: "true"
traefik.http.services.app-svc.loadbalancer.server.port: "8080"
networks:
edge:
external: true
Signification : C’est la configuration rendue après le merge Compose, l’interpolation des variables d’environnement et le parsing YAML. C’est la vérité.
Décision : Si les labels rendus diffèrent (guillemets manquants, chaînes tronquées), corrigez le fichier Compose source. Déboguer le mauvais fichier est un classique auto-infligé.
Trois mini-histoires du monde d’entreprise
Mini-histoire 1 : L’incident causé par une mauvaise hypothèse
Ils migraient une application client d’une config Nginx écrite à la main vers Traefik avec des labels Docker. Le plan semblait correct : chaque service avait des labels et il y avait un réseau « edge » propre. Quelqu’un avait même écrit un README, ce qui est un signe que ça allait faire mal.
La mauvaise hypothèse : « Si le conteneur est accessible depuis l’hôte, Traefik peut aussi y accéder. » Ils avaient exposé l’app sur 0.0.0.0:8080 pour les tests et confirmé via curl http://host:8080. Puis ils ont retiré le mapping de port parce que « Traefik gère maintenant l’ingress ».
Déploiement en prod : Traefik a renvoyé 404 pour le nom d’hôte. On a chassé le DNS, puis les certificats, puis « peut-être le load balancer ». Pendant ce temps, le service était sain et les logs calmes. L’équipe app proposait des rollbacks. L’équipe plateforme invoquait la prière.
Le souci était ennuyeux : Traefik était configuré avec --providers.docker.network=edge, mais le conteneur app était seulement attaché au réseau Compose par défaut. Traefik n’a jamais vu d’endpoint utilisable. Pas de réseau, pas de service, pas de route.
La correction prit cinq minutes : attacher l’app à edge et redéployer. Le postmortem prit plus de temps, car la partie difficile n’était pas la correction ; c’était admettre qu’ils avaient « testé » un chemin réseau différent de celui utilisé en production.
Mini-histoire 2 : L’optimisation qui s’est retournée contre eux
Une autre entreprise avait une initiative « labels minimaux ». L’idée n’était pas folle : trop de labels sont difficiles à lire et les erreurs de copier-coller existent. Ils ont donc retiré les labels explicites de port de service, s’appuyant sur la détection automatique de Traefik. Ça a marché pour la plupart des services. Voilà le piège : le succès partiel est la forme la plus coûteuse d’échec.
Plus tard, un service ajouta un second port exposé pour les métriques. Docker montra deux candidats. Traefik en choisit un. C’était le mauvais. Les requêtes furent routées vers l’endpoint metrics, qui répondait vite mais pas utilement. Les clients voyaient des 404 et des réponses « not found ». Rien n’était techniquement down ; tout était pratiquement cassé.
L’astreinte blâma d’abord un mauvais déploiement. Le rollback n’a rien changé parce que l’exposition du port metrics restait. Ils ont accusé Traefik. Ils ont augmenté les ressources. Ils ont ajusté les timeouts. Ils ont ajouté des retries (ce qui a rendu le bruit plus important).
La vraie correction fut d’annuler l’« optimisation » et de pinner le label du port service. La leçon n’était pas « la détection automatique est mauvaise ». La leçon était : en production, l’ambiguïté est un bug que vous n’avez pas encore rencontré.
Mini-histoire 3 : La pratique ennuyeuse mais correcte qui a sauvé la mise
Une équipe fintech avait l’habitude d’un rituel qui paraissait cérémonial : tout changement de reverse-proxy exigeait une « répétition de route » en staging, incluant une requête scriptée des APIs routers et services de Traefik. Ils ne se fient pas au dashboard. Ils ne se fient pas à l’œil. Ils exécutent un script et archivèrent la sortie avec le ticket de changement.
Lors d’un déploiement de routine, un développeur renomma un router de billing en billing-app mais oublia de mettre à jour la référence middleware. Traefik loggea une erreur sur le middleware manquant, mais la route servit toujours le trafic—simplement sans le middleware d’auth qui limitait l’accès interne uniquement.
Dans beaucoup d’organisations, c’est comme ça qu’on obtient un incident de sécurité qui commence par « on ne pensait pas que c’était atteignable ». Ici, la répétition en staging l’a détecté parce que leur script vérifiait que le router avait la chaîne de middlewares attendue attachée.
Ils ont corrigé le label avant qu’il n’atteigne la production. Le rituel ennuyeux ressemblait à de la bureaucratie jusqu’au moment où il a empêché un incident coûteux et humiliant. Voilà à quoi ressemble une « culture de fiabilité » qui fonctionne réellement.
Erreurs courantes : symptôme → cause racine → correction
Ce sont les récidivistes. Si Traefik « échoue silencieusement », c’est généralement l’un d’eux déguisé.
1) Symptom: 404 from Traefik for the correct hostname
Cause racine : La règle du router ne correspond pas (mauvais domaine, mauvais quoting, utilisation de Host() mais le client envoie un autre Host header), ou le router est lié au mauvais entrypoint.
Correction : Vérifiez que le router existe dans l’API, puis comparez la règle à une requête réelle. Assurez-vous que traefik.http.routers.<name>.entrypoints inclut l’entrypoint que vous touchez.
2) Symptom: Router missing entirely in dashboard/API
Cause racine : traefik.enable manquant alors que exposedByDefault=false ; ou des contraintes du provider Docker l’excluent ; ou les clés de labels sont malformées.
Correction : Ajoutez traefik.enable=true ; vérifiez les flags du provider ; validez les labels via docker inspect et docker compose config.
3) Symptom: Router exists, but requests go to the wrong service
Cause racine : Collision de nom de service, sélection implicite de service, ou multiples routers pointant par accident vers un service par défaut partagé.
Correction : Définissez traefik.http.routers.<router>.service=<service> explicitement et utilisez des noms de service uniques par application.
4) Symptom: TLS works sometimes; sometimes you get the default certificate
Cause racine : Le router n’est pas lié à websecure ou tls=true est manquant ; ou incompatibilité SNI ; ou plusieurs instances Traefik derrière un load balancer.
Correction : Assurez-vous que le router a entrypoints=websecure et tls=true. Confirmez que le client utilise le bon nom d’hôte et touche l’instance prévue.
5) Symptom: Middleware “not applied,” but routing works
Cause racine : Mauvais nom de middleware, scope provider mismatched (@docker vs @file), ou middleware défini sur un autre conteneur et mal référencé.
Correction : Vérifiez les logs Traefik pour « middleware does not exist ». Utilisez une source de vérité unique : définissez les middlewares à côté des routers ou dans un provider fichier et référencez-les avec le suffixe.
6) Symptom: 502 Bad Gateway from Traefik
Cause racine : Traefik matche le router mais ne peut pas atteindre l’upstream (mauvais réseau, mauvais port, app écoute seulement sur localhost, conteneur en redémarrage).
Correction : Testez depuis le conteneur Traefik vers l’IP:port upstream. Pincez le port du service. Assurez-vous que l’app se bind sur 0.0.0.0.
7) Symptom: Everything works on HTTP, fails on HTTPS
Cause racine : Le router n’est défini que pour web, ou le router HTTPS manque de configuration TLS / certresolver.
Correction : Créez un router dédié websecure, mettez tls=true, et assurez-vous qu’un certresolver est configuré si nécessaire.
8) Symptom: You changed labels but Traefik behavior didn’t change
Cause racine : Vous avez édité le fichier Compose mais pas redéployé ; ou Traefik n’a pas pris les événements à cause des permissions du socket ; ou vous regardez la mauvaise instance Traefik.
Correction : Redéployez le service ; vérifiez les événements Docker ; vérifiez les logs Traefik pour le rafraîchissement du provider ; confirmez l’instance cible via les logs d’accès.
Blague #2 : Traefik n’« ignore » pas vos labels. Il les interprète d’une manière qui pousse votre futur vous à déposer une plainte.
Listes de contrôle / plan étape par étape
Étape par étape : Créer une route basée sur labels qui n’échouera pas silencieusement
- Choisissez un seul réseau Docker pour le trafic edge (ex.
edge). Mettez Traefik et chaque service routé dessus. - Définissez explicitement le comportement du provider Traefik :
--providers.docker=true--providers.docker.exposedbydefault=false--providers.docker.network=edge
- Pour chaque service :
- Ajoutez
traefik.enable=true. - Créez un router avec un nom stable :
traefik.http.routers.<router>.*. - Lie-le au(x) bon(s) entrypoint(s).
- Mettez
tls=truepour les routers HTTPS. - Définissez
service=<service-name>explicitement. - Définissez
loadbalancer.server.portexplicitement.
- Ajoutez
- Exécutez
docker compose configet vérifiez que les labels rendus sont corrects. - Vérifiez les routers et services via l’API Traefik après le déploiement.
- Testez depuis l’intérieur du conteneur Traefik vers l’IP:port upstream.
- Ensuite seulement déboguez TLS/certs/middlewares.
Checklist : Avant d’accuser Traefik
- Le conteneur et Traefik partagent un réseau que Traefik est configuré pour utiliser.
- Le router existe dans l’API Traefik.
- La règle du router correspond à l’Host et au Path de la requête.
- Le router est lié à l’entrypoint qui reçoit la requête.
- Le port du service est pined et correct.
- L’upstream est joignable depuis le conteneur Traefik.
- Aucun router catch-all ne vole le trafic à cause d’une priorité.
- Les références de middleware existent et sont correctement scopingées.
FAQ
1) Pourquoi j’obtiens un 404 Traefik au lieu d’une erreur quand les labels sont faux ?
Parce que 404 est la réponse correcte quand aucun router ne correspond à la requête. Un router manquant n’est pas une exception d’exécution ; c’est une configuration absente.
2) Mon router existe, mais il ne correspond toujours pas. Quel est le moyen le plus rapide de le prouver ?
Envoyez une requête avec un Host header explicite au même entrypoint que vous testez, puis comparez avec la règle du router depuis l’API de Traefik.
3) Dois-je vraiment citer les valeurs des labels dans Docker Compose ?
Oui. Le parsing YAML et les caractères spéciaux (backticks, virgules, deux-points) sont à l’origine de nombreux « ça marchait chez moi ». Citez-les et passez à autre chose.
4) Quand dois-je utiliser PathPrefix vs Path ?
Path correspond exactement. PathPrefix correspond à un sous-arbre. Pour des APIs, PathPrefix(`/api`) est courant. Soyez explicite et évitez les chevauchements accidentels avec d’autres routers.
5) Pourquoi Traefik route vers le mauvais port ?
Détection automatique. Si Docker expose plusieurs ports (ou l’image en déclare plusieurs), Traefik en choisit un. Pincez le port avec loadbalancer.server.port.
6) Quelle est la différence entre web/websecure et les ports 80/443 ?
web et websecure sont des noms d’entrypoints. Ils correspondent généralement à des ports, mais c’est le nom auquel les routers se lient. Vous pouvez mapper des entrypoints vers n’importe quel port.
7) Pourquoi un middleware « échoue à moitié » sans casser le routage ?
Traefik peut attacher ce qui existe et logguer des erreurs pour ce qui n’existe pas. C’est bien pour la disponibilité, mais dangereux pour les contrôles de sécurité. Traitez les erreurs de middleware comme des échecs de déploiement.
8) Dois-je placer tous les middlewares sur le conteneur Traefik pour centraliser la config ?
Seulement si vous êtes disciplinés. Centraliser peut réduire la duplication, mais augmente la blast radius et encourage les dépendances entremêlées. Pour les petites stacks, gardez les middlewares proches des services qu’ils affectent.
9) Le tableau de bord Traefik est-il sûr à exposer ?
Pas par défaut. Routez-le via websecure, ajoutez un middleware d’auth et évitez api.insecure=true en production. Traitez-le comme une interface d’administration—parce que c’en est une.
10) Comment arrêter l’exposition accidentelle de conteneurs aléatoires ?
Réglez exposedByDefault=false et exigez traefik.enable=true. Ensuite, utilisez un contrôle CI qui échoue si un service n’a pas de labels explicites router/service/port.
Prochaines étapes à faire aujourd’hui
Si les règles de routage Traefik « échouent silencieusement », la correction est rarement magique. C’est de l’hygiène :
- Rendez le routage explicite : noms de router, noms de service, entrypoints, flags TLS et port upstream.
- Standardisez votre pattern de labels pour que chaque service ressemble au même. La cohérence est un outil de débogage.
- Adoptez l’ordre de diagnostic rapide : entrypoint → existence du router → correspondance → reachabilité upstream → middleware/TLS.
- Ajoutez une garde ennuyeuse : un check scripté qui interroge les routers/services de Traefik après le déploiement et affirme les règles et ports attendus.
Quand Traefik est configuré proprement, il n’est pas mystérieux. C’est un routeur de requêtes avec de fortes opinions et peu de patience. Rencontrez-le à mi-chemin : soyez explicite, vérifiez via l’API et arrêtez de faire confiance à ce qui « devrait » marcher.