Aller au contenu
medium

Traefik SSL/TLS : Let's Encrypt, ACME et certificats automatiques

18 min de lecture

Logo traefik

Ce guide vous accompagne dans la configuration de certificats TLS automatiques avec Traefik v3.6. Vous apprendrez à utiliser Let’s Encrypt via le protocole ACME pour obtenir des certificats gratuits, que ce soit par HTTP Challenge (le plus simple) ou DNS Challenge (pour les wildcards et réseaux privés). À la fin, vos services seront accessibles en HTTPS avec des certificats renouvelés automatiquement.

Temps estimé : 20-25 minutes selon votre configuration.

Vous devez avoir un nom de domaine dont les enregistrements DNS pointent vers l’IP de votre serveur Traefik :

Fenêtre de terminal
# Vérifier que votre domaine pointe vers votre serveur
dig +short mon-domaine.com A
# Doit retourner l'IP de votre serveur
ChallengePort requisDirection
HTTP-0180Entrant depuis Internet
TLS-ALPN-01443Entrant depuis Internet
DNS-01AucunSortant vers API DNS

Vérifiez l’accessibilité depuis l’extérieur :

Fenêtre de terminal
# Depuis un autre serveur ou https://www.whatsmyip.org/port-scanner/
nc -zv votre-ip-publique 80
nc -zv votre-ip-publique 443

Ce guide suppose que Traefik est déjà installé. Si ce n’est pas le cas, consultez d’abord Installer Traefik v3.

Si vous utilisez le DNS Challenge, vous aurez besoin d’un accès API à votre provider DNS (Cloudflare, OVH, Route53, etc.).

ACME (Automatic Certificate Management Environment) est le protocole utilisé par Let’s Encrypt pour automatiser la délivrance de certificats. Voici comment ça fonctionne :

  1. Votre serveur demande un certificat pour un domaine (ex: api.exemple.com)
  2. Let’s Encrypt vous lance un défi : “Prouvez que vous contrôlez ce domaine”
  3. Vous relevez le défi (via HTTP, DNS ou TLS selon le type choisi)
  4. Let’s Encrypt vérifie et délivre le certificat

Les certificats Let’s Encrypt sont gratuits et valides 90 jours. Traefik gère automatiquement le renouvellement (généralement 30 jours avant expiration).

ChallengeComment ça marcheQuand l’utiliser
HTTP-01Let’s Encrypt fait une requête HTTP sur /.well-known/acme-challenge/Port 80 accessible, cas le plus courant
DNS-01Vous créez un enregistrement TXT _acme-challenge.domaineWildcard, port 80 fermé, réseau privé
TLS-ALPN-01Vérification via TLS sur le port 443Port 80 fermé mais 443 ouvert

Un Certificate Resolver est la configuration qui indique à Traefik comment obtenir des certificats. Vous le définissez dans la configuration statique :

# traefik.yaml - Configuration statique
certificatesResolvers:
letsencrypt:
acme:
email: "admin@votre-domaine.com" # Email pour les notifications
storage: /etc/traefik/acme.json # Où stocker les certificats
caServer: "https://acme-v02.api.letsencrypt.org/directory"
httpChallenge:
entryPoint: web # Entrypoint pour le challenge HTTP

Les certificats obtenus sont stockés dans un fichier JSON. Ce fichier doit avoir des permissions strictes car il contient vos clés privées :

Fenêtre de terminal
# Créer le fichier avec les bonnes permissions
touch /etc/traefik/acme.json
chmod 600 /etc/traefik/acme.json

Avec Docker, créez le fichier avant de lancer le conteneur :

Fenêtre de terminal
mkdir -p ~/traefik/certs
touch ~/traefik/certs/acme.json
chmod 600 ~/traefik/certs/acme.json

Une fois le resolver configuré, activez-le sur vos routers :

docker-compose.yml
services:
mon-app:
image: mon-image
labels:
- "traefik.enable=true"
- "traefik.http.routers.mon-app.rule=Host(`app.exemple.com`)"
- "traefik.http.routers.mon-app.entrypoints=websecure"
- "traefik.http.routers.mon-app.tls=true"
- "traefik.http.routers.mon-app.tls.certresolver=letsencrypt"

C’est la méthode la plus simple. Let’s Encrypt vérifie que vous contrôlez le domaine en faisant une requête HTTP sur le port 80.

┌──────────────────────────────────────────────────────────────┐
│ HTTP-01 Challenge │
└──────────────────────────────────────────────────────────────┘
1. Traefik demande un certificat pour app.exemple.com
2. Let's Encrypt génère un token unique
3. Let's Encrypt fait une requête :
GET http://app.exemple.com/.well-known/acme-challenge/{token}
4. Traefik répond avec la preuve de contrôle
5. Let's Encrypt délivre le certificat
  1. Configurer les entrypoints

    Vous avez besoin de deux entrypoints : un pour HTTP (port 80) et un pour HTTPS (port 443) :

    traefik.yaml
    entryPoints:
    web:
    address: ":80"
    websecure:
    address: ":443"
  2. Configurer le certificate resolver

    traefik.yaml
    certificatesResolvers:
    letsencrypt:
    acme:
    email: "admin@exemple.com"
    storage: /etc/traefik/acme.json
    httpChallenge:
    entryPoint: web
  3. Activer TLS sur vos services

    # docker-compose.yml - Service avec HTTPS
    services:
    whoami:
    image: traefik/whoami
    labels:
    - "traefik.enable=true"
    - "traefik.http.routers.whoami.rule=Host(`whoami.exemple.com`)"
    - "traefik.http.routers.whoami.entrypoints=websecure"
    - "traefik.http.routers.whoami.tls.certresolver=letsencrypt"
  4. Redirection HTTP vers HTTPS (optionnel mais recommandé)

    Ajoutez une redirection automatique dans les entrypoints :

    traefik.yaml
    entryPoints:
    web:
    address: ":80"
    http:
    redirections:
    entryPoint:
    to: websecure
    scheme: https
    permanent: true
  5. Vérifier le certificat

    Fenêtre de terminal
    # Attendre quelques secondes que le certificat soit généré
    curl -v https://whoami.exemple.com 2>&1 | grep -A5 "Server certificate"
    # Ou avec openssl
    echo | openssl s_client -connect whoami.exemple.com:443 -servername whoami.exemple.com 2>/dev/null | openssl x509 -noout -issuer -subject -dates

    Résultat attendu :

    issuer=C = US, O = Let's Encrypt, CN = R3
    subject=CN = whoami.exemple.com
    notBefore=Feb 17 12:00:00 2026 GMT
    notAfter=May 18 12:00:00 2026 GMT

Le DNS Challenge est nécessaire pour les certificats wildcard (ex: *.exemple.com) ou quand le port 80 n’est pas accessible depuis Internet.

SituationHTTP ChallengeDNS Challenge
Port 80 ouvert
Port 80 fermé (entreprise)
Certificat wildcard
Réseau privé (homelab)
Multi-domaines sur un certificat

Traefik supporte plus de 100 providers DNS. Voici les plus courants :

ProviderProvider nameVariables d’environnement
CloudflarecloudflareCF_API_EMAIL, CF_DNS_API_TOKEN
OVHovhOVH_ENDPOINT, OVH_APPLICATION_KEY, OVH_APPLICATION_SECRET, OVH_CONSUMER_KEY
AWS Route53route53AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION
Google Cloud DNSgcloudGCE_PROJECT, credentials file
Azure DNSazureAZURE_CLIENT_ID, AZURE_CLIENT_SECRET, AZURE_TENANT_ID, AZURE_SUBSCRIPTION_ID, AZURE_RESOURCE_GROUP
HetznerhetznerHETZNER_API_KEY
DigitalOceandigitaloceanDO_AUTH_TOKEN

La liste complète est disponible sur lego DNS providers.

  1. Créer un token API Cloudflare

    Dans Cloudflare Dashboard → My Profile → API Tokens → Create Token :

    • Template : Edit zone DNS
    • Zone Resources : Include → Specific zone → votre domaine
    • Copiez le token généré
  2. Configurer le resolver avec DNS Challenge

    traefik.yaml
    certificatesResolvers:
    letsencrypt-dns:
    acme:
    email: "admin@exemple.com"
    storage: /etc/traefik/acme.json
    dnsChallenge:
    provider: cloudflare
    propagation:
    delayBeforeChecks: 10s
    resolvers:
    - "1.1.1.1:53"
    - "8.8.8.8:53"
  3. Passer les variables d’environnement

    docker-compose.yml
    services:
    traefik:
    image: traefik:v3.6.7
    environment:
    - CF_API_EMAIL=votre-email@exemple.com
    - CF_DNS_API_TOKEN=votre-token-cloudflare
    # ...
  4. Configurer un certificat wildcard

    services:
    traefik:
    labels:
    - "traefik.http.routers.wildcard.tls.certresolver=letsencrypt-dns"
    - "traefik.http.routers.wildcard.tls.domains[0].main=exemple.com"
    - "traefik.http.routers.wildcard.tls.domains[0].sans=*.exemple.com"
  1. Créer les clés API OVH

    Rendez-vous sur https://eu.api.ovh.com/createToken/ et créez un token avec les droits :

    • GET /domain/zone/*
    • POST /domain/zone/*
    • DELETE /domain/zone/*
  2. Configurer Traefik

    traefik.yaml
    certificatesResolvers:
    letsencrypt-dns:
    acme:
    email: "admin@exemple.com"
    storage: /etc/traefik/acme.json
    dnsChallenge:
    provider: ovh
    propagation:
    delayBeforeChecks: 30s # OVH peut être lent
  3. Variables d’environnement

    docker-compose.yml
    environment:
    - OVH_ENDPOINT=ovh-eu
    - OVH_APPLICATION_KEY=xxx
    - OVH_APPLICATION_SECRET=xxx
    - OVH_CONSUMER_KEY=xxx

Let’s Encrypt impose des limites strictes en production :

LimiteValeur
Certificats par domaine50 / semaine
Échecs de validation5 / heure / compte
Nouveaux enregistrements10 / 3 heures / IP

Ajoutez le serveur staging dans votre configuration :

traefik.yaml
certificatesResolvers:
letsencrypt-staging:
acme:
email: "admin@exemple.com"
storage: /etc/traefik/acme-staging.json # Fichier séparé !
caServer: "https://acme-staging-v02.api.letsencrypt.org/directory"
httpChallenge:
entryPoint: web

Utilisez ce resolver pour vos tests :

- "traefik.http.routers.test.tls.certresolver=letsencrypt-staging"

Une fois que le staging fonctionne :

  1. Changez le resolver vers letsencrypt (production)
  2. Supprimez le fichier acme-staging.json
  3. Redémarrez Traefik
Fenêtre de terminal
rm /etc/traefik/acme-staging.json
docker compose restart traefik

Définissez des profils TLS réutilisables pour contrôler les versions et cipher suites :

config/dynamic/tls.yaml
tls:
options:
# Profil moderne (TLS 1.3 uniquement)
modern:
minVersion: VersionTLS13
sniStrict: true
# Profil intermédiaire (compatibilité TLS 1.2)
intermediate:
minVersion: VersionTLS12
cipherSuites:
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305

Appliquez un profil à un router :

# Docker labels
- "traefik.http.routers.secure-app.tls.options=modern@file"

Le SNI (Server Name Indication) permet d’héberger plusieurs certificats sur une même IP. Avec sniStrict: true, Traefik rejette les connexions qui ne fournissent pas de SNI valide :

tls:
options:
strict:
minVersion: VersionTLS12
sniStrict: true # Rejette les connexions sans SNI

Activez HSTS (HTTP Strict Transport Security) via un middleware :

config/dynamic/middlewares.yaml
http:
middlewares:
hsts:
headers:
stsSeconds: 31536000 # 1 an
stsIncludeSubdomains: true
stsPreload: true
forceSTSHeader: true

Appliquez-le à vos routers :

- "traefik.http.routers.app.middlewares=hsts@file"

Traefik renouvelle automatiquement les certificats 30 jours avant leur expiration. Vous n’avez rien à faire.

Le processus se déclenche au démarrage de Traefik et vérifie tous les certificats stockés dans acme.json.

Surveillez les certificats avec les métriques Prometheus :

traefik.yaml
metrics:
prometheus:
entryPoint: metrics
addServicesLabels: true

Métrique disponible : traefik_tls_certs_not_after_timestamp

Exemple d’alerte Alertmanager :

- alert: CertificateExpiringSoon
expr: (traefik_tls_certs_not_after_timestamp - time()) / 86400 < 14
for: 1h
labels:
severity: warning
annotations:
summary: "Certificat expire dans moins de 14 jours"

Si vous devez forcer un renouvellement :

Fenêtre de terminal
# Sauvegarder puis supprimer le certificat
cp /etc/traefik/acme.json /etc/traefik/acme.json.bak
# Supprimer uniquement le certificat concerné (avec jq)
jq 'del(.letsencrypt.Certificates[] | select(.domain.main == "exemple.com"))' \
/etc/traefik/acme.json > /tmp/acme.json && mv /tmp/acme.json /etc/traefik/acme.json
# Redémarrer Traefik
docker compose restart traefik

Un lab complet est disponible pour tester toutes ces configurations :

Fenêtre de terminal
cd ~/Projets/lab-traefik-tls-acme
lab-traefik-tls-acme/
├── docker-compose.yml # Stack Docker
├── config/
│ ├── traefik.yaml # Configuration statique
│ └── dynamic/
│ ├── tls.yaml # Options TLS
│ └── middlewares.yaml # Middlewares HTTPS
└── certs/
└── acme.json # Stockage certificats (chmod 600)
Fenêtre de terminal
# Créer le fichier de certificats
touch certs/acme.json && chmod 600 certs/acme.json
# Démarrer avec certificats auto-signés (pour tests locaux)
docker compose up -d
# Vérifier les logs
docker compose logs -f traefik
# Tester
curl -k https://localhost:8443 -H "Host: whoami.localhost"

Symptôme : pas de certificat, erreur 526 ou certificat auto-signé affiché.

Vérifications :

Fenêtre de terminal
# 1. Vérifier les logs Traefik
docker compose logs traefik | grep -i acme
# 2. Vérifier que le port 80 est accessible
curl http://votre-domaine.com
# 3. Vérifier le DNS
dig +short votre-domaine.com A
# 4. Vérifier le fichier acme.json
cat /etc/traefik/acme.json | jq '.letsencrypt'

Solutions courantes :

ErreurCauseSolution
”acme: error validating”Port 80 bloquéOuvrir le firewall ou utiliser DNS Challenge
”too many certificates”Rate limit atteintAttendre 1 semaine ou utiliser staging
”DNS problem”DNS mal configuréVérifier les enregistrements A/AAAA

Vous avez atteint la limite Let’s Encrypt. Options :

  1. Attendre : la limite se réinitialise après 7 jours
  2. Utiliser staging : pas de limite pour les tests
  3. Utiliser un wildcard : un seul certificat pour tous les sous-domaines

Avec le DNS Challenge, Let’s Encrypt peut ne pas voir l’enregistrement TXT à temps.

# Augmenter le délai
certificatesResolvers:
letsencrypt-dns:
acme:
dnsChallenge:
provider: ovh
propagation:
delayBeforeChecks: 60s # Augmenter à 60s voire plus

Vous pouvez aussi spécifier des resolvers DNS rapides :

resolvers:
- "1.1.1.1:53" # Cloudflare
- "8.8.8.8:53" # Google

Si votre certificat est signé par “Fake LE” en production :

  1. Vérifiez que vous utilisez le bon resolver (pas -staging)
  2. Supprimez acme.json et redémarrez pour forcer un nouveau certificat
  3. Vérifiez les logs pour les erreurs ACME
  • Let’s Encrypt fournit des certificats TLS gratuits et automatiques via le protocole ACME
  • HTTP Challenge est le plus simple (port 80 requis), DNS Challenge permet les wildcards
  • Toujours tester avec staging avant de passer en production pour éviter les rate limits
  • Le fichier acme.json doit avoir les permissions 600 (lecture/écriture propriétaire uniquement)
  • Traefik renouvelle automatiquement les certificats 30 jours avant expiration
  • Utilisez les TLS Options pour définir des profils de sécurité réutilisables

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.