
Ce guide vous apprend à configurer les middlewares Traefik en construisant pas à pas un environnement de test. Chaque middleware est présenté avec un cas d'usage, une configuration minimale, et une commande curl pour valider que ça fonctionne.
À la fin, vous saurez :
- Protéger une API avec rate limiting et headers de sécurité
- Sécuriser un backoffice avec authentification et filtrage IP
- Exposer un site public avec compression et protection anti-abus
Public cible : développeurs et ops utilisant Traefik comme reverse proxy.
Prérequis : Docker installé. Ce guide utilise Docker Compose pour le lab.
Accès rapide aux middlewares
Section intitulée « Accès rapide aux middlewares »Vous êtes pressé ? Allez directement au middleware qui vous intéresse :
| Besoin | Middleware | Section |
|---|---|---|
Supprimer /api de l'URL | stripPrefix | Réécriture |
| Ajouter un préfixe | addPrefix | Réécriture |
| Protection par mot de passe | basicAuth | Authentification |
| SSO (Authelia, Keycloak) | forwardAuth | Authentification |
| Limiter les requêtes/seconde | rateLimit | Protection |
| Filtrer par IP | ipAllowList | Protection |
| Limiter requêtes simultanées | inFlightReq | Protection |
| Couper si backend KO | circuitBreaker | Protection |
| Headers de sécurité | headers | Réponse |
| CORS | headers (CORS) | Réponse |
| Compression gzip/brotli | compress | Réponse |
| HTTP → HTTPS | redirectScheme | Redirections |
| Grouper des middlewares | chain | Chaînage |
Recettes prêtes à copier :
- Site public : rate limit + headers + compress
- Backoffice interne : IP filter + SSO + headers
- API publique : rate limit + CORS + headers
Setup du lab (5 min)
Section intitulée « Setup du lab (5 min) »Tout le guide repose sur ce lab. Vous allez créer un environnement Traefik + whoami qui sert de terrain d'expérimentation pour tous les middlewares.
Structure du lab
Section intitulée « Structure du lab »Le lab tient en trois fichiers, et cette séparation reflète l'architecture de
Traefik : la configuration statique (traefik.yml) est lue une seule fois au
démarrage, tandis que la configuration dynamique (config/middlewares.yml)
est rechargée à chaud à chaque modification. C'est pour cette raison que les
middlewares vivent dans le second fichier et non le premier.
traefik-lab/├── docker-compose.yml├── traefik.yml # Config statique└── config/ └── middlewares.yml # Middlewares (config dynamique)Fichiers à créer
Section intitulée « Fichiers à créer »Créez ces trois fichiers dans l'ordre. Le premier lance Traefik et deux
services whoami qui renvoient les détails de la requête reçue, ce qui permet
de vérifier visuellement l'effet de chaque middleware. Les deux suivants
configurent Traefik lui-même. Le montage de docker.sock en lecture seule
(:ro) suffit à Traefik pour découvrir les conteneurs.
1. docker-compose.yml
services: traefik: image: traefik:v3.7.6@sha256:21a3d83696379bac6434bb32e1dde0aff0e84ef2abd053ed3db87d3f45e749b2 ports: - "80:80" - "8080:8080" # Dashboard volumes: - ./traefik.yml:/etc/traefik/traefik.yml:ro - ./config:/etc/traefik/config:ro - /var/run/docker.sock:/var/run/docker.sock:ro labels: - "traefik.enable=true"
# Service de test principal whoami: image: traefik/whoami:v1.11.0@sha256:200689790a0a0ea48ca45992e0450bc26ccab5307375b41c84dfc4f2475937ab labels: - "traefik.enable=true" - "traefik.http.routers.whoami.rule=Host(`whoami.localhost`)" - "traefik.http.routers.whoami.entrypoints=web"
# API de test (même image, route différente) api: image: traefik/whoami:v1.11.0@sha256:200689790a0a0ea48ca45992e0450bc26ccab5307375b41c84dfc4f2475937ab labels: - "traefik.enable=true" - "traefik.http.routers.api.rule=Host(`whoami.localhost`) && PathPrefix(`/api`)" - "traefik.http.routers.api.entrypoints=web"2. traefik.yml (config statique)
api: dashboard: true insecure: true # Dashboard sans auth (lab uniquement)
entryPoints: web: address: ":80"
providers: docker: exposedByDefault: false file: directory: /etc/traefik/config watch: true
log: level: INFO3. config/middlewares.yml (vide pour l'instant)
http: middlewares: {}Démarrer le lab
Section intitulée « Démarrer le lab »Une fois les trois fichiers en place, un seul docker compose up -d suffit à
tout lancer. L'option -d détache les conteneurs pour rendre la main ; les
logs restent consultables avec docker compose logs -f traefik si le démarrage
échoue.
mkdir -p traefik-lab/configcd traefik-lab# Créer les fichiers ci-dessus, puis :docker compose up -dVérifier que le lab fonctionne
Section intitulée « Vérifier que le lab fonctionne »# Site principalcurl http://whoami.localhost# → Affiche infos whoami (IP, headers...)
# Route APIcurl http://whoami.localhost/api# → Même chose, mais via /api
# Dashboard Traefikopen http://localhost:8080Le lab est prêt. Tous les exemples qui suivent utilisent ce setup.
Glossaire
Section intitulée « Glossaire »Ces termes reviennent dans toute la documentation Traefik et dans les messages d'erreur. Gardez surtout à l'esprit la distinction entre un middleware (qui transforme ou bloque une requête) et un router (qui décide où l'envoyer) : c'est la confusion la plus fréquente quand un middleware semble ne pas s'appliquer.
| Terme | Définition |
|---|---|
| Middleware | Fonction qui intercepte une requête entre le client et le backend pour la transformer ou la bloquer |
| Chain | Groupe de middlewares exécutés dans l'ordre |
| Router | Règle qui détermine vers quel service envoyer la requête |
| Service | Cible de la requête (backend, load balancer) |
| Entrypoint | Port d'écoute de Traefik (ex: 80, 443) |
| AuthN | Authentification, vérifier l'identité ("qui êtes-vous ?") |
| AuthZ | Autorisation, vérifier les permissions ("avez-vous le droit ?") |
| Token bucket | Algorithme de rate limiting : un "seau" se remplit de tokens, chaque requête en consomme un |
| SSE | Server-Sent Events, flux de données en temps réel du serveur vers le client |
| CORS | Cross-Origin Resource Sharing, mécanisme permettant à un site d'accéder à des ressources d'un autre domaine |
Mental model : où s'exécute un middleware ?
Section intitulée « Mental model : où s'exécute un middleware ? »Position dans le flux Traefik
Section intitulée « Position dans le flux Traefik »
Un middleware s'exécute après que le routeur a décidé où va la requête, et avant qu'elle n'atteigne le backend. Il peut :
- Bloquer la requête (rate limit, auth, IP filter)
- Transformer la requête (strip prefix, add header)
- Modifier la réponse (headers, compression)
Règle d'or : "Bloquer tôt, transformer tard"
Section intitulée « Règle d'or : "Bloquer tôt, transformer tard" »L'ordre des middlewares est critique. Appliquez cette règle :
Pourquoi ?
- Bloquer tôt économise des ressources : inutile d'authentifier une IP bannie
- Transformer tard garantit que les modifications passent au backend/client
Ordre recommandé
Section intitulée « Ordre recommandé »Ce tableau traduit la règle précédente en séquence concrète. Lisez-le de haut en
bas : c'est l'ordre dans lequel placer les middlewares d'une chain. Les deux
premières étapes rejettent les requêtes indésirables au plus tôt, les
suivantes ne s'appliquent donc qu'au trafic déjà filtré, ce qui évite de
compresser ou de réécrire une requête qui aurait de toute façon été bloquée.
| Étape | Middlewares | Objectif |
|---|---|---|
| 1 | ipAllowList, rateLimit, inFlightReq | Bloquer les abus |
| 2 | basicAuth, forwardAuth | Vérifier l'identité |
| 3 | stripPrefix, addPrefix, replacePath | Réécrire les chemins |
| 4 | headers (response) | Ajouter headers de sécurité |
| 5 | compress | Compresser la réponse |
Recettes prêtes à l'emploi
Section intitulée « Recettes prêtes à l'emploi »Avant de détailler chaque middleware, voici 3 chains complètes couvrant 90% des cas d'usage. Copiez celle qui correspond à votre besoin.
Recette A, Site public (blog, docs, vitrine)
Section intitulée « Recette A, Site public (blog, docs, vitrine) »Objectif : protection anti-abus + headers de sécurité + compression.
http: middlewares: chain-public-web: chain: middlewares: - rate-limit-web - secure-headers-web - compress-web
rate-limit-web: rateLimit: average: 100 burst: 200
secure-headers-web: headers: frameDeny: true contentTypeNosniff: true stsSeconds: 31536000 stsIncludeSubdomains: true
compress-web: compress: excludedContentTypes: - text/event-streamAppliquer au lab (docker-compose.yml) :
whoami: labels: - "traefik.http.routers.whoami.middlewares=chain-public-web@file"✅ Vérifier :
# Headers de sécurité présentscurl -I http://whoami.localhost# → X-Frame-Options: DENY# → X-Content-Type-Options: nosniff# → Strict-Transport-Security: max-age=31536000
# Compression activecurl -H "Accept-Encoding: gzip" -I http://whoami.localhost# → Content-Encoding: gzipRecette B, Backoffice interne (admin, outils internes)
Section intitulée « Recette B, Backoffice interne (admin, outils internes) »Objectif : accès restreint par IP + authentification SSO.
http: middlewares: chain-internal-app: chain: middlewares: - ip-filter-internal - auth-internal - secure-headers-internal
ip-filter-internal: ipAllowList: sourceRange: - "10.0.0.0/8" - "192.168.0.0/16" - "172.16.0.0/12"
auth-internal: forwardAuth: address: http://authelia:9091/api/verify trustForwardHeader: false authResponseHeaders: - X-Forwarded-User
secure-headers-internal: headers: frameDeny: true contentTypeNosniff: true✅ Vérifier :
# Depuis une IP non autorisée → 403curl http://admin.localhost# → 403 Forbidden
# Depuis une IP autorisée, sans auth → 401 (ou redirect SSO)curl http://admin.localhost# → 401 UnauthorizedRecette C, API publique (REST, GraphQL)
Section intitulée « Recette C, API publique (REST, GraphQL) »Objectif : rate limiting strict + CORS + headers de sécurité.
http: middlewares: chain-api: chain: middlewares: - rate-limit-api - cors-api - secure-headers-api
rate-limit-api: rateLimit: average: 60 burst: 100 period: 1m sourceCriterion: ipStrategy: depth: 1
cors-api: headers: accessControlAllowMethods: - GET - POST - PUT - DELETE - OPTIONS accessControlAllowHeaders: - Authorization - Content-Type accessControlAllowOriginList: - "https://app.example.com" accessControlMaxAge: 86400
secure-headers-api: headers: contentTypeNosniff: true customResponseHeaders: Cache-Control: "no-store"Appliquer au lab :
api: labels: - "traefik.http.routers.api.middlewares=chain-api@file"✅ Vérifier :
# CORS headers présentscurl -I -X OPTIONS http://whoami.localhost/api \ -H "Origin: https://app.example.com" \ -H "Access-Control-Request-Method: POST"# → Access-Control-Allow-Origin: https://app.example.com
# Rate limit (envoyer 200 requêtes)for i in {1..200}; do curl -s -o /dev/null -w "%{http_code}\n" http://whoami.localhost/api; done# → 429 Too Many Requests après dépassementMiddlewares par famille
Section intitulée « Middlewares par famille »Maintenant, détaillons chaque middleware avec une structure répétable :
- 🟢 Quand l'utiliser (+ 2 cas concrets)
- 🔴 Quand ne pas l'utiliser
- Configuration minimale
- ✅ Vérifier (test curl)
- Pièges fréquents
- 🟠 Variante avancée (optionnel)
Famille 1 : Réécriture des chemins
Section intitulée « Famille 1 : Réécriture des chemins »Ces middlewares modifient l'URL avant qu'elle n'atteigne le backend.
StripPrefix, Supprimer un préfixe
Section intitulée « StripPrefix, Supprimer un préfixe »🟢 Quand l'utiliser :
- Vous exposez
/api/usersmais le backend attend/users - Vous avez un préfixe de versioning (
/v1/...) que le backend ne comprend pas
🔴 Quand ne pas l'utiliser :
- Le backend gère déjà le préfixe (framework avec routing)
Configuration minimale :
http: middlewares: strip-api: stripPrefix: prefixes: - /apiAppliquer au lab :
api: labels: - "traefik.http.routers.api.middlewares=strip-api@file"✅ Vérifier :
# Requête vers /api/testcurl http://whoami.localhost/api/test# → Dans la sortie whoami : "GET /test HTTP/1.1"# (le /api a été retiré)Pièges fréquents :
- Le backend renvoie des URLs avec le chemin original (sans
/api) → les liens internes cassent - Oublier que
stripPrefixlaisse un/initial :/api/users→/users(pasusers)
🟠 Variante avancée, StripPrefixRegex :
strip-versions: stripPrefixRegex: regex: - "^/v[0-9]+/"Retire /v1/, /v2/, etc.
AddPrefix, Ajouter un préfixe
Section intitulée « AddPrefix, Ajouter un préfixe »addPrefix fait l'inverse de stripPrefix : il préfixe le chemin reçu avant
de le transmettre au backend. Le client interroge une URL courte, le backend
reçoit une URL enrichie, sans qu'aucun des deux n'ait à connaître la
transformation.
🟢 Quand l'utiliser :
- Le backend attend un préfixe que vous ne voulez pas exposer
- Migration : ancien chemin → nouveau chemin interne
🔴 Quand ne pas l'utiliser :
- Le prefixe est déjà dans l'URL du client
Configuration minimale :
http: middlewares: add-v2: addPrefix: prefix: /v2✅ Vérifier :
curl http://whoami.localhost/users# → Backend reçoit : "GET /v2/users HTTP/1.1"Pièges fréquents :
- Double préfixe si combiné avec stripPrefix dans le mauvais ordre
ReplacePath, Remplacer le chemin entier
Section intitulée « ReplacePath, Remplacer le chemin entier »Là où stripPrefix et addPrefix modifient une partie du chemin, replacePath
écrase le chemin en entier par une valeur fixe. Le chemin d'origine est
perdu pour le backend, sauf s'il est conservé dans un header, ce que fait la
variante replacePathRegex.
🟢 Quand l'utiliser :
- Rediriger toutes les requêtes d'une route vers un chemin fixe
- Endpoint de health check unique
🔴 Quand ne pas l'utiliser :
- Vous voulez conserver une partie du chemin original
Configuration minimale :
http: middlewares: health-redirect: replacePath: path: /health✅ Vérifier :
curl http://whoami.localhost/anything# → Backend reçoit : "GET /health HTTP/1.1"Famille 2 : Authentification
Section intitulée « Famille 2 : Authentification »BasicAuth, Authentification simple
Section intitulée « BasicAuth, Authentification simple »🟢 Quand l'utiliser :
- Protection rapide d'un service interne (dev, staging)
- Accès temporaire à un outil sans SSO
🔴 Quand ne pas l'utiliser :
- En production sans HTTPS (credentials en clair !)
- Applications avec beaucoup d'utilisateurs (pas de gestion de sessions)
Configuration minimale :
# Générer le hash (bcrypt recommandé)htpasswd -nbB admin "monsecret"# → admin:$2y$05$...http: middlewares: basic-auth: basicAuth: users: - "admin:$2y$05$XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"Appliquer au lab :
whoami: labels: - "traefik.http.routers.whoami.middlewares=basic-auth@file"✅ Vérifier :
# Sans credentials → 401curl http://whoami.localhost# → 401 Unauthorized
# Avec credentials → 200curl -u admin:monsecret http://whoami.localhost# → Réponse whoamiPièges fréquents :
- Hash mal généré (MD5 au lieu de bcrypt) → refusé
- Oublier d'échapper les
$dans Docker labels - Utiliser en production sans HTTPS
🟠 Variante avancée, Fichier htpasswd :
basic-auth-file: basicAuth: usersFile: /etc/traefik/htpasswd removeHeader: true # Ne pas transmettre le header au backendForwardAuth, Déléguer l'authentification
Section intitulée « ForwardAuth, Déléguer l'authentification »🟢 Quand l'utiliser :
- SSO avec Authelia, Keycloak, Authentik
- Authentification centralisée multi-services
🔴 Quand ne pas l'utiliser :
- Service interne simple (préférez BasicAuth)
- Le service auth n'est pas résilient (single point of failure)
Configuration minimale :
http: middlewares: auth-sso: forwardAuth: address: http://authelia:9091/api/verify authResponseHeaders: - X-Forwarded-User - X-Forwarded-Groups✅ Vérifier :
# Sans session → 401 ou 302 (redirect vers login)curl -I http://whoami.localhost# → HTTP/1.1 302 Found# → Location: https://auth.example.com/login?rd=...
# Avec cookie de session valide → 200curl -b "authelia_session=xxx" http://whoami.localhostPièges fréquents :
trustForwardHeader: truesans proxy de confiance → usurpation d'identitéauthResponseHeadersmal configuré → headers sensibles transmis au client (smuggling)- Service auth lent → augmenter les timeouts
🟠 Variante avancée, trustForwardHeader :
auth-behind-proxy: forwardAuth: address: http://authelia:9091/api/verify trustForwardHeader: true # SEULEMENT si derrière un proxy de confiance authResponseHeaders: - X-Forwarded-UserDigestAuth, Authentification digest
Section intitulée « DigestAuth, Authentification digest »🟢 Quand l'utiliser :
- Clients qui ne supportent pas BasicAuth moderne
- Légèrement plus sécurisé que BasicAuth (pas de mot de passe en clair)
🔴 Quand ne pas l'utiliser :
- En production (HTTPS + BasicAuth bcrypt est meilleur)
- Applications modernes (préférez ForwardAuth + SSO)
Configuration minimale :
http: middlewares: digest-auth: digestAuth: users: - "admin:traefik:hash"Voir la documentation officielle pour la génération du hash.
Famille 3 : Protection et résilience
Section intitulée « Famille 3 : Protection et résilience »RateLimit, Limiter les requêtes
Section intitulée « RateLimit, Limiter les requêtes »🟢 Quand l'utiliser :
- Protéger une API contre les abus
- Éviter qu'un client monopolise les ressources
🔴 Quand ne pas l'utiliser :
- Services internes entre microservices (latence ajoutée)
- Quand vous avez un WAF en amont qui fait déjà du rate limiting
Configuration minimale :
http: middlewares: rate-limit: rateLimit: average: 10 # 10 req/s en moyenne burst: 20 # Jusqu'à 20 en rafaleAppliquer au lab :
api: labels: - "traefik.http.routers.api.middlewares=rate-limit@file"✅ Vérifier :
# Envoyer 30 requêtes rapidementfor i in {1..30}; do curl -s -o /dev/null -w "%{http_code} " http://whoami.localhost/apidone# → 200 200 200 ... 429 429 429Pièges fréquents :
sourceCriterion.requestHeaderNameavec un header spoofable (X-Real-IP) → bypass- Oublier que Traefik utilise un token bucket (le burst permet des pics)
- Rate limit trop agressif → faux positifs pour les utilisateurs légitimes
🟠 Variante avancée, Par API key :
rate-limit-by-key: rateLimit: average: 100 burst: 200 period: 1m sourceCriterion: requestHeaderName: X-API-Key # SEULEMENT émis par un service de confianceIPAllowList, Filtrer par IP
Section intitulée « IPAllowList, Filtrer par IP »ipAllowList n'autorise que les adresses appartenant aux plages CIDR
déclarées, et renvoie 403 à toutes les autres. Le point de vigilance est la
provenance de l'IP examinée : derrière un load balancer, c'est l'IP du LB qui
arrive, d'où le paramètre ipStrategy.depth détaillé plus bas.
🟢 Quand l'utiliser :
- Restreindre l'accès à un backoffice par IP
- Whitelister des partenaires ou un VPN
🔴 Quand ne pas l'utiliser :
- IPs dynamiques (FAI résidentiels)
- Alternative à l'authentification (IP != identité)
Configuration minimale :
http: middlewares: ip-whitelist: ipAllowList: sourceRange: - "192.168.1.0/24" - "10.0.0.0/8"✅ Vérifier :
# Depuis une IP autorisée → 200curl http://whoami.localhost
# Depuis une IP non autorisée → 403curl http://whoami.localhost# → 403 ForbiddenPièges fréquents :
- Oublier
ipStrategy.depthderrière un load balancer → bloque le LB, pas le client - Plages CIDR mal calculées
🟠 Variante avancée, Derrière un proxy :
ip-whitelist-behind-lb: ipAllowList: sourceRange: - "192.168.1.0/24" ipStrategy: depth: 1 # Prend l'IP dans X-Forwarded-ForInFlightReq, Limiter les requêtes simultanées
Section intitulée « InFlightReq, Limiter les requêtes simultanées »🟢 Quand l'utiliser :
- Protéger un backend fragile contre la surcharge
- Limiter le nombre de connexions longues (websockets, SSE)
🔴 Quand ne pas l'utiliser :
- APIs stateless rapides (rate limit est plus adapté)
Configuration minimale :
http: middlewares: inflight: inFlightReq: amount: 10 # Max 10 requêtes simultanées par source✅ Vérifier :
# Lancer 20 requêtes lentes en parallèlefor i in {1..20}; do curl -s "http://whoami.localhost/api?delay=5s" &done# → Les 10 premières passent, les suivantes reçoivent 503Pièges fréquents :
- Confondre avec rate limit (qui compte sur le temps, pas les requêtes actives)
sourceCriterionmal configuré → limite globale au lieu de par IP
CircuitBreaker, Couper si backend défaillant
Section intitulée « CircuitBreaker, Couper si backend défaillant »🟢 Quand l'utiliser :
- Protéger les utilisateurs d'un backend instable
- Éviter de saturer un service défaillant avec des retries
🔴 Quand ne pas l'utiliser :
- Backend toujours sain (overhead inutile)
- Quand vous préférez des erreurs explicites (fail fast)
Configuration minimale :
http: middlewares: circuit-breaker: circuitBreaker: expression: "NetworkErrorRatio() > 0.30"Comportement : si plus de 30% des requêtes échouent (erreurs réseau), le circuit s'ouvre et renvoie 503 pendant fallbackDuration (10s par défaut).
✅ Vérifier :
Difficile à tester sans simuler des erreurs backend. En lab, vous pouvez arrêter le service whoami :
docker compose stop whoami# Les requêtes vers whoami déclenchent le circuit après quelques échecsPièges fréquents :
- Expression mal calibrée → circuit s'ouvre trop vite ou jamais
- Oublier
checkPeriodetrecoveryDurationpour le retour à la normale
🟠 Variante avancée, Paramètres de timing :
circuit-breaker-tuned: circuitBreaker: expression: "NetworkErrorRatio() > 0.25 || ResponseCodeRatio(500, 600, 0, 600) > 0.30" checkPeriod: 10s # Fréquence de vérification fallbackDuration: 15s # Durée en mode "ouvert" recoveryDuration: 30s # Durée de récupération progressiveFamille 4 : Réponse (headers, compression)
Section intitulée « Famille 4 : Réponse (headers, compression) »Headers, Ajouter des headers de sécurité
Section intitulée « Headers, Ajouter des headers de sécurité »🟢 Quand l'utiliser :
- Toujours sur les services web (HSTS, X-Frame-Options, CSP)
- Ajouter des headers métier (X-Request-ID, X-API-Version)
🔴 Quand ne pas l'utiliser :
- Le backend gère déjà ces headers (duplication)
Configuration minimale :
http: middlewares: secure-headers: headers: frameDeny: true # X-Frame-Options: DENY contentTypeNosniff: true # X-Content-Type-Options: nosniff browserXssFilter: true # X-XSS-Protection: 1; mode=block stsSeconds: 31536000 # HSTS 1 an stsIncludeSubdomains: trueAppliquer au lab :
whoami: labels: - "traefik.http.routers.whoami.middlewares=secure-headers@file"✅ Vérifier :
curl -I http://whoami.localhost# → X-Frame-Options: DENY# → X-Content-Type-Options: nosniff# → Strict-Transport-Security: max-age=31536000; includeSubDomainsPièges fréquents :
- HSTS sur un site sans HTTPS → les utilisateurs seront bloqués
- CSP trop restrictive → casse le site (tester d'abord en mode report-only)
🟠 Variante avancée, CSP complète :
secure-headers-csp: headers: contentSecurityPolicy: "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'" customResponseHeaders: X-Robots-Tag: "noindex, nofollow"Headers CORS, Autoriser les requêtes cross-origin
Section intitulée « Headers CORS, Autoriser les requêtes cross-origin »🟢 Quand l'utiliser :
- API consommée par un frontend sur un autre domaine
- Applications SPA (React, Vue, Angular)
🔴 Quand ne pas l'utiliser :
- API interne entre microservices (même origine)
- Quand le framework backend gère déjà CORS
Configuration minimale :
http: middlewares: cors: headers: accessControlAllowMethods: - GET - POST - OPTIONS accessControlAllowOriginList: - "https://app.example.com" accessControlMaxAge: 86400✅ Vérifier :
# Preflight OPTIONScurl -I -X OPTIONS http://whoami.localhost/api \ -H "Origin: https://app.example.com" \ -H "Access-Control-Request-Method: POST"# → Access-Control-Allow-Origin: https://app.example.com# → Access-Control-Allow-Methods: GET, POST, OPTIONSCompress, Compresser les réponses
Section intitulée « Compress, Compresser les réponses »🟢 Quand l'utiliser :
- Sites web avec beaucoup de contenu texte (HTML, CSS, JS)
- APIs JSON volumineuses
🔴 Quand ne pas l'utiliser :
- Contenu déjà compressé (images, vidéos)
- Flux temps réel (SSE, WebSocket), voir note ci-dessous
Configuration minimale :
http: middlewares: compress: compress: {}Appliquer au lab :
whoami: labels: - "traefik.http.routers.whoami.middlewares=compress@file"✅ Vérifier :
# Demander gzipcurl -H "Accept-Encoding: gzip" -I http://whoami.localhost# → Content-Encoding: gzip
# Demander brotli (prioritaire si supporté)curl -H "Accept-Encoding: br, gzip" -I http://whoami.localhost# → Content-Encoding: brPièges fréquents :
- Compression sur des réponses tiny → overhead
- Compression + SSE → latence au lieu de temps réel
🟠 Variante avancée, Taille minimale :
compress-smart: compress: minResponseBodyBytes: 1024 # Compresser seulement si > 1 KB excludedContentTypes: - text/event-streamPriorité des algorithmes : Traefik choisit brotli (br) si le client le supporte, sinon gzip. Brotli offre une meilleure compression mais est plus lent.
Redirections
Section intitulée « Redirections »RedirectScheme, HTTP vers HTTPS
Section intitulée « RedirectScheme, HTTP vers HTTPS »🟢 Quand l'utiliser :
- Forcer HTTPS sur tous les services
🔴 Quand ne pas l'utiliser :
- Environnement de dev local sans certificat
Configuration minimale :
http: middlewares: redirect-https: redirectScheme: scheme: https permanent: true # 301 au lieu de 302✅ Vérifier :
curl -I http://whoami.localhost# → HTTP/1.1 301 Moved Permanently# → Location: https://whoami.localhost/RedirectRegex, Redirections par expression régulière
Section intitulée « RedirectRegex, Redirections par expression régulière »redirectRegex capture des morceaux de l'URL avec une expression régulière et
les réinjecte dans l'URL de destination via des groupes (${1}, ${2}). C'est
l'outil des redirections qui dépendent du contenu de l'URL, là où redirectScheme
se contente de changer le protocole.
🟢 Quand l'utiliser :
- Rediriger
www.vers apex (ou inversement) - Migrations d'URLs complexes
🔴 Quand ne pas l'utiliser :
- Redirections simples (préférez RedirectScheme ou record DNS CNAME)
Configuration minimale :
http: middlewares: redirect-www: redirectRegex: regex: "^https://www\\.(.*)" replacement: "https://${1}" permanent: true✅ Vérifier :
curl -I https://www.example.com# → HTTP/1.1 301 Moved Permanently# → Location: https://example.comChaînage de middlewares
Section intitulée « Chaînage de middlewares »Créer une chain
Section intitulée « Créer une chain »Objectif : grouper plusieurs middlewares pour les réutiliser.
http: middlewares: # Middlewares unitaires rate-limit: rateLimit: average: 100 burst: 200
secure-headers: headers: frameDeny: true contentTypeNosniff: true
compress: compress: {}
# Chain qui les combine chain-web: chain: middlewares: - rate-limit - secure-headers - compressUtilisation :
whoami: labels: - "traefik.http.routers.whoami.middlewares=chain-web@file"Ordre dans une chain
Section intitulée « Ordre dans une chain »L'ordre dans la liste middlewares est l'ordre d'exécution :
chain: middlewares: - rate-limit # 1. Bloque les abus - basic-auth # 2. Vérifie l'identité - strip-prefix # 3. Transforme l'URL - secure-headers # 4. Ajoute headers - compress # 5. Compresse la réponseDépannage orienté symptômes
Section intitulée « Dépannage orienté symptômes »Symptôme : middleware ignoré
Section intitulée « Symptôme : middleware ignoré »Observations :
- Les headers attendus ne sont pas présents
- L'authentification ne se déclenche pas
Causes probables :
-
Nom mal orthographié, Vérifiez que le nom dans
middlewares:correspond exactement à la définition -
Mauvais provider, Un middleware File Provider se référence avec
@file, un Docker avec@docker:- middleware-name@file # File provider- middleware-name@docker # Docker provider -
Namespace Kubernetes, Le middleware doit être dans le même namespace ou référencé avec
namespace-name@kubernetescrd
Diagnostic :
# Lister les middlewares connus par Traefikcurl http://localhost:8080/api/http/middlewares | jq '.[].name'Symptôme : 401 Unauthorized inattendu
Section intitulée « Symptôme : 401 Unauthorized inattendu »Un 401 alors que les identifiants sont corrects vient presque toujours du
hachage du mot de passe ou de l'échappement des caractères spéciaux dans les
labels Docker. Commencez par ces deux points avant de suspecter le service
d'authentification.
Observations :
- L'utilisateur a des credentials valides mais reçoit 401
Causes probables :
-
Hash mal généré, Vérifiez que vous utilisez bcrypt (
htpasswd -nbB) -
$ non échappé, Dans Docker labels, doublez les
$:$$2y$$05$$... -
ForwardAuth : service auth inaccessible, Vérifiez que le service auth répond :
Fenêtre de terminal curl http://authelia:9091/api/verify
Symptôme : 429 Too Many Requests
Section intitulée « Symptôme : 429 Too Many Requests »Un 429 qui frappe des utilisateurs légitimes signale soit une limite trop
basse, soit un sourceCriterion qui range tout le monde dans le même compteur.
Le second cas est le plus courant derrière un proxy : toutes les requêtes
semblent partir de la même adresse.
Observations :
- Rate limit se déclenche pour des utilisateurs légitimes
Causes probables :
-
Limites trop agressives, Augmentez
averageetburst -
sourceCriterion mal configuré, Tous les utilisateurs partagent la même limite :
sourceCriterion:ipStrategy:depth: 0 # IP directe du client -
Derrière un proxy sans X-Forwarded-For, Toutes les requêtes semblent venir de la même IP
Symptôme : headers de sécurité absents
Section intitulée « Symptôme : headers de sécurité absents »Quand les headers attendus n'apparaissent pas dans la réponse, la cause est
presque toujours un middleware non rattaché au routeur ou un ordre
d'exécution qui les fait écraser. Vérifiez d'abord le label middlewares= avant
de mettre en cause la configuration du middleware lui-même.
Observations :
curl -Ine montre pas les headers attendus
Causes probables :
-
Middleware non attaché au routeur, Vérifiez le label
middlewares= -
Backend renvoie déjà ces headers, Traefik n'écrase pas les headers existants par défaut
-
Ordre des middlewares, Un autre middleware écrase les headers
Symptôme : ForwardAuth timeout (500)
Section intitulée « Symptôme : ForwardAuth timeout (500) »Un 500 accompagné de context deadline exceeded indique que Traefik n'obtient
pas de réponse du service d'authentification dans le délai imparti. Le
problème est réseau ou de performance, jamais une question de credentials.
Observations :
- Erreur 500 avec "context deadline exceeded" dans les logs
Causes probables :
-
Service auth lent, Le service d'authentification met trop de temps
-
Mauvaise URL,
addresspointe vers un service inaccessible
Solution, Vérifiez la connectivité :
# Depuis le conteneur Traefikdocker exec -it traefik wget -q -O- http://authelia:9091/api/verifyCheck-list finale
Section intitulée « Check-list finale »Avant de déployer vos middlewares en production, vérifiez :
-
HTTPS activé, BasicAuth et headers de sécurité n'ont de sens qu'avec TLS
-
Ordre correct, Rate limit et IP filter avant l'authentification
-
Tests curl effectués, Chaque middleware validé individuellement
-
Logs consultés, Pas d'erreur dans
docker logs traefik -
Dashboard vérifié, Middlewares visibles dans l'API
À retenir
Section intitulée « À retenir »-
Un middleware est un filtre, il transforme, vérifie ou protège entre le client et le backend.
-
Bloquer tôt, transformer tard, rate limit avant auth, headers et compress en dernier.
-
Chaînez avec
chain, groupez les middlewares par cas d'usage (public, internal, api). -
Testez avec curl, chaque middleware a une commande de validation simple.
-
BasicAuth sans HTTPS = danger, préférez ForwardAuth + SSO en production.