Pourquoi Traefik ?
Dès qu'un serveur héberge plusieurs applications conteneurisées, il faut un reverse proxy devant elles : un seul point d'entrée sur les ports 80 et 443, qui route chaque domaine vers le bon conteneur et gère le HTTPS. Nginx sait très bien le faire, mais chaque nouvelle application demande d'écrire un virtual host, de recharger la configuration et de générer un certificat.
Traefik inverse la logique : il lit l'API Docker, découvre les conteneurs, et les configure à partir de leurs labels. Démarrer un conteneur suffit pour le publier en HTTPS, avec un certificat Let's Encrypt obtenu et renouvelé automatiquement.
Le réseau partagé
Traefik et les applications qu'il expose doivent partager un réseau Docker. Créez-le une fois pour toutes :
docker network create proxy
Traefik lui-même
Un fichier /opt/traefik/compose.yaml :
services:
traefik:
image: traefik:v3.5
restart: unless-stopped
command:
- --providers.docker=true
- --providers.docker.exposedbydefault=false
- --providers.docker.network=proxy
- --entrypoints.web.address=:80
- --entrypoints.web.http.redirections.entrypoint.to=websecure
- --entrypoints.web.http.redirections.entrypoint.scheme=https
- --entrypoints.websecure.address=:443
- [email protected]
- --certificatesresolvers.le.acme.storage=/letsencrypt/acme.json
- --certificatesresolvers.le.acme.httpchallenge.entrypoint=web
- --api.dashboard=true
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./letsencrypt:/letsencrypt
networks:
- proxy
labels:
- traefik.enable=true
- traefik.http.routers.dashboard.rule=Host(`traefik.example.com`)
- traefik.http.routers.dashboard.entrypoints=websecure
- traefik.http.routers.dashboard.tls.certresolver=le
- traefik.http.routers.dashboard.service=api@internal
- traefik.http.routers.dashboard.middlewares=dashboard-auth
- traefik.http.middlewares.dashboard-auth.basicauth.users=admin:$$apr1$$Hq3vN2kS$$exempleDeHashAremplacer
networks:
proxy:
external: true
Quelques points importants :
exposedbydefault=false: aucun conteneur n'est publié sanstraefik.enable=true. Sans cette option, une base de données démarrée par erreur pourrait se retrouver exposée.- La redirection HTTP → HTTPS est déclarée une fois, au niveau de l'entrypoint
web. - Le socket Docker est monté en lecture seule. Il donne tout de même beaucoup de pouvoir sur l'hôte : pour un durcissement supplémentaire, placez un proxy de socket (comme
tecnativa/docker-socket-proxy) entre Traefik et Docker. - Dans un fichier Compose, les
$du hash doivent être doublés ($$). Générez le hash avechtpasswd -nb admin motdepasse(paquetapache2-utils).
cd /opt/traefik && docker compose up -d
docker compose logs -f traefik
Publier une application
Côté application, il suffit de rejoindre le réseau proxy et de décrire le routage en labels. Exemple avec un conteneur Symfony (PHP-FPM + Nginx dans l'image, sur le port 8080) :
services:
app:
image: ghcr.io/moi/app:latest
restart: unless-stopped
env_file: .env.prod
networks:
- proxy
- internal
labels:
- traefik.enable=true
- traefik.http.routers.app.rule=Host(`app.example.com`) || Host(`www.app.example.com`)
- traefik.http.routers.app.entrypoints=websecure
- traefik.http.routers.app.tls.certresolver=le
- traefik.http.routers.app.middlewares=secure-headers,rate-limit
- traefik.http.services.app.loadbalancer.server.port=8080
- traefik.http.middlewares.secure-headers.headers.stsSeconds=31536000
- traefik.http.middlewares.secure-headers.headers.stsIncludeSubdomains=true
- traefik.http.middlewares.secure-headers.headers.contentTypeNosniff=true
- traefik.http.middlewares.secure-headers.headers.frameDeny=true
- traefik.http.middlewares.rate-limit.ratelimit.average=50
- traefik.http.middlewares.rate-limit.ratelimit.burst=100
database:
image: mysql:8.4
restart: unless-stopped
environment:
MYSQL_DATABASE: app
MYSQL_USER: app
MYSQL_PASSWORD_FILE: /run/secrets/db_password
MYSQL_RANDOM_ROOT_PASSWORD: "yes"
secrets:
- db_password
volumes:
- db-data:/var/lib/mysql
networks:
- internal
networks:
proxy:
external: true
internal:
volumes:
db-data:
secrets:
db_password:
file: ./secrets/db_password.txt
La base de données n'est reliée qu'au réseau internal : Traefik ne peut pas l'atteindre, et elle n'a aucun port publié. Au premier docker compose up -d, Traefik détecte le conteneur, obtient le certificat pour les deux domaines et commence à router le trafic, en quelques secondes et sans aucun redémarrage.
Lire un label de routage
Les labels suivent tous la même grammaire : traefik.http.<type>.<nom>.<option>.
- routers : quelle requête (règle
Host,PathPrefix…) arrive sur quel entrypoint, avec quel TLS et quels middlewares - services : vers quel port du conteneur envoyer le trafic (indispensable si l'image expose plusieurs ports)
- middlewares : les transformations appliquées en chemin (en-têtes, authentification, limitation de débit, redirections, compression)
Un middleware déclaré sur un conteneur peut être réutilisé par les autres : définissez vos en-têtes de sécurité une fois, sur le conteneur Traefik, puis référencez-les avec le suffixe @docker, par exemple secure-headers@docker.
Certificats wildcard avec le challenge DNS
Le challenge HTTP nécessite que le serveur soit joignable sur le port 80. Pour un certificat *.example.com, ou un serveur non exposé, utilisez le challenge DNS. Avec Cloudflare par exemple :
- --certificatesresolvers.le.acme.dnschallenge=true
- --certificatesresolvers.le.acme.dnschallenge.provider=cloudflare
environment:
CF_DNS_API_TOKEN_FILE: /run/secrets/cf_token
Le jeton Cloudflare n'a besoin que de la permission Zone → DNS → Edit sur la zone concernée.
Dépannage
- Erreur 404 « page not found » : le routeur n'existe pas. Vérifiez
traefik.enable=trueet la règleHost(les backticks sont obligatoires). - Erreur 502 Bad Gateway : Traefik trouve le conteneur mais ne le joint pas. Le conteneur est-il sur le réseau
proxy? Le port duloadbalancerest-il le bon ? - Certificat auto-signé « TRAEFIK DEFAULT CERT » : le challenge ACME a échoué. Consultez les logs de Traefik ; le DNS pointe-t-il vers le serveur, et le port 80 est-il ouvert ?
- Limite de Let's Encrypt : pendant vos essais, utilisez le serveur de test (
--certificatesresolvers.le.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory) pour ne pas atteindre les quotas.
Une fois en place, ajouter une application revient à écrire trois ou quatre labels. C'est ce qui rend Traefik si agréable pour un serveur personnel ou une petite infrastructure qui héberge beaucoup de services.