Skip to Content
Config🚦 Traefik

🚦 Traefik

Reverse proxy moderne et dynamique, parfait pour les environnements Docker.

Traefik détecte automatiquement les services Docker et configure le routage via les labels.

Installation avec Docker Compose

Configuration de base

version: '3.8' services: traefik: image: traefik:v3.0 container_name: traefik restart: unless-stopped security_opt: - no-new-privileges:true ports: - "80:80" - "443:443" volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - ./traefik.yml:/traefik.yml:ro - ./acme.json:/acme.json - ./config:/config:ro networks: - proxy networks: proxy: external: true

Fichier traefik.yml

api: dashboard: true insecure: true # À désactiver en production entryPoints: http: address: ":80" http: redirections: entryPoint: to: https scheme: https https: address: ":443" providers: docker: endpoint: "unix:///var/run/docker.sock" exposedByDefault: false network: proxy file: directory: /config watch: true certificatesResolvers: letsencrypt: acme: email: ton@email.com storage: acme.json httpChallenge: entryPoint: http

Labels Docker

Service basique

services: app: image: mon-app labels: - "traefik.enable=true" - "traefik.http.routers.app.rule=Host(`app.example.com`)" - "traefik.http.routers.app.entrypoints=https" - "traefik.http.routers.app.tls.certresolver=letsencrypt" - "traefik.http.services.app.loadbalancer.server.port=3000" networks: - proxy

Règles de routage

# Par domaine - "traefik.http.routers.app.rule=Host(`app.example.com`)" # Par chemin - "traefik.http.routers.app.rule=PathPrefix(`/api`)" # Combiné - "traefik.http.routers.app.rule=Host(`example.com`) && PathPrefix(`/api`)" # Plusieurs domaines - "traefik.http.routers.app.rule=Host(`app.example.com`) || Host(`www.app.example.com`)" # Avec regex sur le path - "traefik.http.routers.app.rule=Host(`example.com`) && PathPrefix(`/api/{version:v[0-9]+}`)"

Middlewares

Redirection HTTP vers HTTPS

labels: - "traefik.http.middlewares.redirect-https.redirectscheme.scheme=https" - "traefik.http.middlewares.redirect-https.redirectscheme.permanent=true" - "traefik.http.routers.app-http.middlewares=redirect-https"

Basic Auth

labels: # Générer le hash: echo $(htpasswd -nb user password) | sed -e s/\\$/\\$\\$/g - "traefik.http.middlewares.auth.basicauth.users=user:$$apr1$$..." - "traefik.http.routers.app.middlewares=auth"

N’oublie pas de doubler les $ dans les fichiers Docker Compose pour échapper le caractère.

Headers de sécurité

labels: - "traefik.http.middlewares.security-headers.headers.frameDeny=true" - "traefik.http.middlewares.security-headers.headers.contentTypeNosniff=true" - "traefik.http.middlewares.security-headers.headers.browserXssFilter=true" - "traefik.http.middlewares.security-headers.headers.stsSeconds=31536000" - "traefik.http.middlewares.security-headers.headers.stsIncludeSubdomains=true" - "traefik.http.routers.app.middlewares=security-headers"

Rate Limiting

labels: - "traefik.http.middlewares.rate-limit.ratelimit.average=100" - "traefik.http.middlewares.rate-limit.ratelimit.burst=50" - "traefik.http.routers.app.middlewares=rate-limit"

IP Whitelist

labels: - "traefik.http.middlewares.whitelist.ipwhitelist.sourcerange=192.168.1.0/24,10.0.0.0/8" - "traefik.http.routers.app.middlewares=whitelist"

Strip Prefix

labels: # Retire /api du path avant d'envoyer au service - "traefik.http.middlewares.strip-api.stripprefix.prefixes=/api" - "traefik.http.routers.app.middlewares=strip-api"

Chaîner les middlewares

labels: - "traefik.http.routers.app.middlewares=redirect-https,security-headers,rate-limit"

Certificats SSL

Let’s Encrypt automatique

# Dans traefik.yml certificatesResolvers: letsencrypt: acme: email: ton@email.com storage: acme.json httpChallenge: entryPoint: http
# Dans le service labels: - "traefik.http.routers.app.tls=true" - "traefik.http.routers.app.tls.certresolver=letsencrypt"

Wildcard avec DNS Challenge (Cloudflare)

# Dans traefik.yml certificatesResolvers: letsencrypt: acme: email: ton@email.com storage: acme.json dnsChallenge: provider: cloudflare resolvers: - "1.1.1.1:53" - "8.8.8.8:53"
# Variables d'environnement pour Traefik environment: - CF_API_EMAIL=ton@email.com - CF_API_KEY=ton-api-key
# Dans le service labels: - "traefik.http.routers.app.tls.certresolver=letsencrypt" - "traefik.http.routers.app.tls.domains[0].main=example.com" - "traefik.http.routers.app.tls.domains[0].sans=*.example.com"

Dashboard Traefik

Accès sécurisé au dashboard

services: traefik: labels: - "traefik.enable=true" - "traefik.http.routers.dashboard.rule=Host(`traefik.example.com`)" - "traefik.http.routers.dashboard.entrypoints=https" - "traefik.http.routers.dashboard.tls.certresolver=letsencrypt" - "traefik.http.routers.dashboard.service=api@internal" - "traefik.http.routers.dashboard.middlewares=auth" - "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$..."

Exemples complets

Application web classique

version: '3.8' services: app: image: nginx:alpine restart: unless-stopped labels: - "traefik.enable=true" - "traefik.http.routers.app.rule=Host(`app.example.com`)" - "traefik.http.routers.app.entrypoints=https" - "traefik.http.routers.app.tls.certresolver=letsencrypt" - "traefik.http.services.app.loadbalancer.server.port=80" - "traefik.http.routers.app.middlewares=security-headers" networks: - proxy networks: proxy: external: true

API avec sous-chemin

version: '3.8' services: api: image: mon-api restart: unless-stopped labels: - "traefik.enable=true" - "traefik.http.routers.api.rule=Host(`example.com`) && PathPrefix(`/api`)" - "traefik.http.routers.api.entrypoints=https" - "traefik.http.routers.api.tls.certresolver=letsencrypt" - "traefik.http.services.api.loadbalancer.server.port=8080" - "traefik.http.middlewares.api-strip.stripprefix.prefixes=/api" - "traefik.http.routers.api.middlewares=api-strip,rate-limit" networks: - proxy networks: proxy: external: true

Stack complète avec base de données

version: '3.8' services: frontend: image: mon-frontend restart: unless-stopped labels: - "traefik.enable=true" - "traefik.http.routers.frontend.rule=Host(`app.example.com`)" - "traefik.http.routers.frontend.entrypoints=https" - "traefik.http.routers.frontend.tls.certresolver=letsencrypt" - "traefik.http.services.frontend.loadbalancer.server.port=80" networks: - proxy - internal backend: image: mon-backend restart: unless-stopped environment: - DATABASE_URL=postgres://user:pass@db:5432/app labels: - "traefik.enable=true" - "traefik.http.routers.backend.rule=Host(`app.example.com`) && PathPrefix(`/api`)" - "traefik.http.routers.backend.entrypoints=https" - "traefik.http.routers.backend.tls.certresolver=letsencrypt" - "traefik.http.services.backend.loadbalancer.server.port=3000" networks: - proxy - internal db: image: postgres:15-alpine restart: unless-stopped volumes: - postgres_data:/var/lib/postgresql/data environment: - POSTGRES_USER=user - POSTGRES_PASSWORD=pass - POSTGRES_DB=app networks: - internal volumes: postgres_data: networks: proxy: external: true internal:

Commandes utiles

# Créer le network proxy docker network create proxy # Créer le fichier acme.json avec les bonnes permissions touch acme.json && chmod 600 acme.json # Voir les logs de Traefik docker logs -f traefik # Générer un hash pour Basic Auth echo $(htpasswd -nb user password) | sed -e s/\\$/\\$\\$/g

Debugging

Active le mode debug temporairement pour diagnostiquer les problèmes.

# Dans traefik.yml log: level: DEBUG accessLog: {}

Vérifier la configuration

# Voir les routers configurés curl http://localhost:8080/api/http/routers | jq # Voir les services curl http://localhost:8080/api/http/services | jq # Voir les middlewares curl http://localhost:8080/api/http/middlewares | jq