Pourquoi placer Traefik en frontal de votre VPS ?
Quand vous faites tourner plusieurs applications conteneurisées sur un même VPS, gérer manuellement les virtual hosts Nginx et renouveler chaque certificat devient vite ingérable. Traefik résout ce problème en lisant directement les labels de vos conteneurs Docker : vous déclarez une route au moment du docker run ou dans votre docker-compose.yml, et Traefik la configure à chaud, génère le certificat Let's Encrypt et l'expose en HTTPS. Aucun fichier de conf à éditer, aucun reload : tout est dynamique.
Nginx reste un excellent serveur HTTP, mais sa configuration est statique : chaque nouveau service demande un vhost, un nginx -s reload et un outil ACME à part (certbot et sa tâche de renouvellement). Traefik a été pensé pour une topologie qui change sans cesse, ce qui est exactement le cas d'un VPS où l'on ajoute, met à jour et retire des conteneurs chaque semaine. La branche v3, publiée en avril 2024, a stabilisé HTTP/3 et l'export de traces en OpenTelemetry, et durci la syntaxe des règles de routage.
Ce que Traefik apporte concrètement sur un VPS
- Découverte automatique des conteneurs Docker via le provider Docker (les routes apparaissent sans redémarrage)
- Certificats SSL Let's Encrypt générés et renouvelés automatiquement (challenges HTTP-01, TLS-ALPN-01 ou DNS-01), renouvelés par défaut 30 jours avant leur expiration
- Routage par domaine, par chemin ou par en-tête, géré entièrement via les labels Docker
- Dashboard web intégré pour visualiser routers, services et middlewares en temps réel
- Middlewares prêts à l'emploi : redirection HTTPS, basic auth, rate limiting, headers de sécurité, compression
- Load balancing automatique quand vous scalez un service à plusieurs réplicas
- HTTP/3 (QUIC) activable sur un entrypoint en une option
- D'autres providers que Docker (Swarm, Kubernetes, Nomad, fichiers) si votre infrastructure grandit
Prérequis
Traefik lui-même est très léger : 1 vCPU et 1 Go de RAM suffisent largement pour le proxy seul, le surcoût venant de vos applications derrière. Prévoyez un VPS sous Debian 12 ou Ubuntu 22.04/24.04 avec Docker Engine et le plugin Docker Compose v2 installés (la commande docker compose, sans tiret), un nom de domaine dont les enregistrements A/AAAA pointent vers l'IP du VPS avant le premier démarrage (sans quoi Let's Encrypt ne peut pas valider le domaine), et les ports 80 et 443 ouverts en entrée dans votre pare-feu (UFW), en TCP, plus 443 en UDP si vous activez HTTP/3. Gardez une adresse e-mail valide pour le compte ACME. Pour les certificats wildcard, il vous faudra aussi un accès API à votre fournisseur DNS.
Déployer Traefik avec Docker Compose
Créer le réseau et l'arborescence
Créez un réseau Docker partagé que Traefik et vos applications utiliseront, puis un dossier dédié contenant le fichier
acme.json(le stockage des certificats et de leurs clés privées) :docker network create proxy mkdir -p /opt/traefik && cd /opt/traefik touch acme.json && chmod 600 acme.jsonCréez le fichier avant le premier démarrage : si le chemin monté n'existe pas, Docker crée un dossier à sa place et Traefik ne peut plus y écrire. Les droits 600 sont exigés : Traefik refuse un fichier lisible par d'autres utilisateurs.
Configurer les entrypoints et le résolveur ACME
Placez ce fichier dans
/opt/traefik/docker-compose.yml. Il déclare deux entrypoints (websur :80,websecuresur :443), un certificateResolver Let's Encrypt validé par le challenge HTTP, la découverte des conteneurs par le socket Docker monté en lecture seule, et le dashboard :services: traefik: image: traefik:v3.7 container_name: traefik restart: unless-stopped ports: - "80:80" - "443:443" - "443:443/udp" 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" - "--entrypoints.websecure.http3=true" - "[email protected]" - "--certificatesresolvers.letsencrypt.acme.storage=/acme.json" - "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web" - "--api.dashboard=true" volumes: - "/var/run/docker.sock:/var/run/docker.sock:ro" - "./acme.json:/acme.json" 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=letsencrypt" - "traefik.http.routers.dashboard.service=api@internal" - "traefik.http.routers.dashboard.middlewares=dashboard-auth" - "traefik.http.middlewares.dashboard-auth.basicauth.users=admin:$$2y$$05$$REMPLACER_PAR_LE_HASH" networks: proxy: external: trueL'option
exposedbydefault=falseest essentielle : sans elle, chaque conteneur du VPS serait publié, y compris votre base de données. Épinglez la branche (v3.7) plutôt quelatest, et suivez les releases avant de changer de version mineure.Forcer la redirection HTTP vers HTTPS
La redirection se déclare directement sur l'entrypoint
web, avec les deux options--entrypoints.web.http.redirections.entrypoint.to=websecureet...entrypoint.scheme=httpsdéjà présentes dans le fichier ci-dessus. C'est plus simple et plus sûr qu'un router « catch-all » avec middleware : tout trafic en clair est basculé en HTTPS par une redirection permanente, sans label à répéter sur chaque service, et le challenge HTTP de Let's Encrypt continue de passer sur le port 80.Sécuriser le dashboard
Le dashboard est exposé sur
traefik.example.com, derrière le middlewarebasicauthnommédashboard-auth. Générez un hash bcrypt (paquetapache2-utilssous Debian/Ubuntu) en doublant les$, comme l'exige une valeur de label dans un fichier Compose :apt install -y apache2-utils htpasswd -nB admin | sed -e 's/\$/\$\$/g'Collez le résultat à la place de
admin:$$2y$$05$$REMPLACER_PAR_LE_HASH. Un hash collé avec des$simples est interprété par Compose comme des variables et casse l'authentification. Ne laissez jamais le flag--api.insecure=trueen production : il publie le dashboard sans authentification.Lancer Traefik
Démarrez la stack et suivez les logs :
cd /opt/traefik docker compose up -d docker compose logs -f traefikVous devez voir le provider Docker démarrer, puis le router
dashboards'attacher, sans erreur ACME. Pendant vos essais, ajoutez temporairement--certificatesresolvers.letsencrypt.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory: le serveur staging de Let's Encrypt délivre des certificats non reconnus par les navigateurs, mais vous protège du rate limit de production si une configuration échoue en boucle. Retirez l'option et videzacme.jsonavant le passage en production.Connecter une application
Chaque application vit dans son propre
docker-compose.yml, rattachée au réseauproxyet décrite par ses labels :services: app: image: ghcr.io/example/app:1.0.0 restart: unless-stopped networks: - proxy labels: - "traefik.enable=true" - "traefik.http.routers.app.rule=Host(`app.example.com`)" - "traefik.http.routers.app.entrypoints=websecure" - "traefik.http.routers.app.tls.certresolver=letsencrypt" - "traefik.http.services.app.loadbalancer.server.port=3000" networks: proxy: external: trueAu
docker compose up -d, Traefik détecte le conteneur, obtient le certificat et active la route en quelques secondes, sans toucher à sa propre configuration. Le labelloadbalancer.server.portindique le port interne de l'application ; il devient indispensable dès que l'image en expose plusieurs. Le nom du router (appici) doit être unique sur tout le VPS.Vérifier le certificat et la redirection
Contrôlez depuis une machine extérieure au VPS :
curl -I http://app.example.com curl -I https://app.example.com dig +short app.example.comLa première requête doit renvoyer une redirection permanente vers
https://, la deuxième un200(ou le code de votre application) servi avec un certificat Let's Encrypt valide, etdigdoit afficher l'IP du VPS. Le dashboard liste aussi chaque router avec son résolveur de certificat. Un port 80 qui refuse la connexion pointe presque toujours vers le pare-feu.
Middlewares utiles en production
Un middleware Traefik se déclare par label, une seule fois, puis s'attache à un ou plusieurs routers par traefik.http.routers.<router>.middlewares=<nom1>,<nom2>. Vous les définissez donc sur le service concerné, sans toucher à la configuration centrale de Traefik. Voici ceux qui servent sur presque tous les VPS.
Cinq middlewares à connaître
- BasicAuth sur un outil d'administration (Adminer, Flower…) :
traefik.http.middlewares.adminauth.basicauth.users=admin:$$2y$$05$$..., puistraefik.http.routers.monadmin.middlewares=adminauth. Même règle de$doublés que pour le dashboard. - Rate limit devant une API ou un formulaire :
traefik.http.middlewares.ratelimit.ratelimit.average=100,...ratelimit.period=1set...ratelimit.burst=200autorisent 100 requêtes par seconde en moyenne, avec des rafales jusqu'à 200. Sansaverage, la limite est désactivée. - Headers de sécurité : le middleware
headerspose HSTS (stsSeconds=31536000,stsIncludeSubdomains=true),X-Frame-Options: DENY(frameDeny=true) etX-Content-Type-Options: nosniff(contentTypeNosniff=true), sans fichier de configuration séparé. - Redirection www vers le domaine nu :
redirectregexavecregex=^https://www\.(.+),replacement=https://$${1}etpermanent=true. Pensez à déclarer les deux hôtes dans la règle du router pour que le certificat couvrewww. - Compression :
traefik.http.middlewares.compress.compress=trueactive gzip, Brotli et Zstandard selon ce qu'accepte le navigateur, sans réglage côté application.
Pour obtenir un certificat wildcard (*.example.com) et éviter d'exposer chaque sous-domaine, passez du httpChallenge au dnsChallenge : c'est le seul challenge qui délivre un wildcard. Avec Cloudflare, déclarez --certificatesresolvers.letsencrypt.acme.dnschallenge.provider=cloudflare et passez à Traefik la variable CF_DNS_API_TOKEN, un jeton API limité aux permissions Zone / DNS / Edit et Zone / Zone / Read. L'ancien couple CF_API_EMAIL + CF_API_KEY fonctionne aussi, mais il exige la clé API globale, qui ouvre tout le compte : préférez le jeton. Traefik prouve alors la propriété du domaine par un enregistrement TXT, ce qui fonctionne même pour des services non exposés publiquement.
Activer HTTP/3 (QUIC)
Le fichier Compose ci-dessus l'active déjà : --entrypoints.websecure.http3=true sur l'entrypoint TLS, et la publication du port 443:443/udp. Traefik écoute alors en UDP sur le même port que l'entrypoint TCP ; une connexion commence toujours en TCP, puis le navigateur bascule en QUIC au voyage suivant. Deux conditions : seuls les routers en TLS sont servis en HTTP/3, et le pare-feu doit laisser passer le port 443 en UDP (ufw allow 443/udp). Si vous publiez un autre port UDP que celui de l'entrypoint, l'option http3.advertisedPort annonce le bon. Pour vérifier, utilisez un curl compilé avec HTTP/3 : curl --http3 -I https://app.example.com.
Venir de Traefik v2 : ce qui casse
La v3 garde la configuration de routage v2 compatible, mais elle change la syntaxe par défaut des règles et refuse de démarrer sur plusieurs options retirées. Pour migrer sans tout réécrire d'un coup, ajoutez --core.defaultRuleSyntax=v2 dans la configuration d'installation : vos anciennes règles continuent de fonctionner, vous passez les routers un par un à la syntaxe v3, puis vous retirez l'option. Les logs de Traefik signalent chaque option dépréciée encore utilisée : lisez-les après le premier démarrage. Les changements qui piègent le plus souvent :
Changements cassants de la v3
- Swarm : l'option
swarmModedu provider Docker n'existe plus et bloque le démarrage. Docker Swarm a désormais son propre provider (--providers.swarm). - Règles de routage :
HeadersetHeadersRegexpdeviennentHeaderetHeaderRegexp,HostHeaderdisparaît au profit deHost, et la plupart des matchers n'acceptent plus qu'une valeur. - Chemins :
PathetPathPrefixne lisent plus d'expression régulière ni de placeholder comme{id}; une telle route ne correspond plus à rien. Passez àPathRegexp, qui suit la syntaxe regexp de Go, commeHostRegexp. - Middlewares renommés ou allégés :
IPWhiteListdevientIPAllowList(mêmes options) ; le middlewareheadersperdsslRedirect,sslTemporaryRedirect,sslHost,sslForceHostetfeaturePolicy. - Content-Type : Traefik ne devine plus le type d'une réponse que le backend n'a pas typée ; ajoutez le middleware
ContentTypesi une application en dépend. - Providers et observabilité retirés : Marathon, Rancher v1, Traefik Pilot et les métriques InfluxDB v1 empêchent le démarrage ; le tracing passe uniquement par OpenTelemetry (plus d'export direct vers Jaeger, Zipkin ou Datadog).
Traefik v3, Nginx ou Caddy devant vos conteneurs
Faites défiler le tableau
| Critère | Traefik v3 | Nginx | Caddy 2 |
|---|---|---|---|
| Configuration | Labels Docker, YAML ou TOML, prise en compte à chaud | Fichiers vhost statiques, `nginx -s reload` à chaque changement | Caddyfile ou API JSON, rechargement sans coupure |
| HTTPS automatique | Intégré (ACME : HTTP-01, TLS-ALPN-01, DNS-01) | Outil externe (certbot) et tâche de renouvellement | Intégré et actif par défaut |
| Découverte des conteneurs | Native, par le socket Docker | Absente : outil tiers ou édition manuelle | Via le module communautaire caddy-docker-proxy |
| HTTP/3 | Stable depuis la v3.0 (avril 2024), une option par entrypoint | Expérimental depuis nginx 1.25.0 (mai 2023), configuration dédiée | Actif par défaut depuis Caddy 2.6 (septembre 2022) |
| Prise en main | Moyenne : routers, services et middlewares à assimiler | Connue de tous, mais HTTPS + Docker demandent de l'outillage | La plus rapide pour quelques sites |
Dépannage : les erreurs les plus fréquentes
La plupart des incidents Traefik viennent de quatre sources : le DNS ou le pare-feu qui empêchent la validation Let's Encrypt, le fichier acme.json, un réseau Docker manquant et des labels mal écrits. Les symptômes et leurs corrections :
Symptômes et corrections
- Certificat non obtenu, erreur ACME
unauthorizedou403dans les logs : Let's Encrypt n'atteint pas votre domaine. Vérifiez depuis l'extérieur que le port 80 répond (curl -I http://app.example.com) et que le DNS pointe sur le VPS (dig +short app.example.com). Derrière un CDN en mode proxy, préférez lednsChallenge. permissions 644 for /acme.json are too open, please use 600: le résolveur refuse le fichier. Corrigez avecchmod 600 /opt/traefik/acme.jsonpuis redémarrez Traefik ; ce contrôle protège les clés privées qui y sont stockées.- Route visible dans le dashboard mais
502 Bad Gateway: le conteneur n'est pas sur le réseauproxy, ou le port interne est faux. Vérifiez avecdocker inspect <conteneur>(sectionNetworks), ajoutez le réseau ou le labelloadbalancer.server.port, puis recréez le conteneur. Sur un conteneur relié à plusieurs réseaux, le labeltraefik.docker.network=proxylève l'ambiguïté. - Labels ignorés, route absente du dashboard : il manque
traefik.enable=true(obligatoire avecexposedbydefault=false), ou deux services déclarent le même nom de router. Les logs de Traefik signalent alors le conflit. - BasicAuth qui refuse un bon mot de passe : les
$du hash ne sont pas doublés dans ledocker-compose.yml. Dans un fichier Compose, chaque$devient$$; dans un fichier de configuration dynamique YAML ou TOML, le hash se colle tel quel.
Prochaine étape : durcir la stack
Traefik règle le routage et le TLS, mais une stack prête pour la production demande davantage : healthchecks, politique de redémarrage, rotation des logs, secrets hors du fichier Compose, sauvegarde des volumes (dont acme.json). Notre check-list Docker Compose en production reprend ces points un par un. Et si vous hésitez encore sur l'outil, le comparatif Caddy, Traefik et Nginx Proxy Manager aide à trancher selon le nombre de services et le besoin de découverte automatique.