Contexte / besoin
Une plateforme auto-hébergée fait tourner en conteneurs Docker des services de natures très différentes : sites clients publics, outils internes privés, API recevant des webhooks. Tous doivent être servis en HTTPS, chacun avec la bonne exposition, sans multiplier les points d’entrée ni la configuration au cas par cas.
Contraintes
- Public et privé cohabitent sur la même machine : une erreur de configuration ne doit pas exposer un service interne à Internet.
- Les certificats doivent se renouveler sans intervention manuelle. Un renouvellement oublié finit en service en panne.
- Un seul mainteneur : la configuration doit rester lisible et reproductible dans six mois.
Options envisagées
- nginx + certbot, le duo classique. Éprouvé, mais la configuration impérative s’éclate par service, et le cycle certbot puis reload reste une mécanique à entretenir.
- Caddy rend le TLS automatique très simple. Il restait moins riche pour mon usage, notamment sur les middlewares composables et l’intégration Docker par labels.
- Traefik v3 : découverte automatique des conteneurs par labels,
middlewares chaînables, ACME intégré. Le service et son exposition se
décrivent au même endroit, dans le
docker-composeversionné.
Décision & pourquoi
Traefik v3, configuration 100 % déclarative (fichiers statiques et labels Docker), versionnée en Git. Exposer un nouveau service se résume à quelques labels sur son conteneur :
# Exposer un service : quelques labels suffisent (domaine d'exemple)
services:
app:
image: ghcr.io/exemple/app:1.4.2
networks: [proxy] # réseau dédié au reverse proxy
labels:
traefik.enable: true
traefik.http.routers.app.rule: Host(`app.exemple.fr`)
traefik.http.routers.app.entrypoints: websecure # HTTPS uniquement
traefik.http.routers.app.middlewares: secure-headers@file
Côté TLS : un certificat wildcard Let’s Encrypt obtenu par challenge DNS-01 via l’API OVH. Deux avantages concrets. Aucun port HTTP à ouvrir pour valider le challenge. Et les sous-domaines ne sont pas énumérés un par un dans les journaux publics de transparence des certificats : un wildcard ne divulgue pas la carte des services.
Tradeoff assumé
Traefik devient la pièce centrale unique : s’il tombe, tout l’edge tombe. Sur une plateforme mono-serveur, ce point de défaillance est accepté. En échange, il n’y a qu’une seule surface à durcir, à superviser et à mettre à jour. La courbe d’apprentissage de Traefik (routers, services, middlewares) est réelle, mais on ne la paie qu’une fois.
Résultat
Tous les services, publics comme privés, passent par le même point d’entrée, avec HTTPS partout et des certificats renouvelés sans intervention depuis la mise en place.
- Fiable : renouvellement TLS automatique, configuration reproductible depuis Git.
- Maintenable : ajouter un service demande quelques labels, et tout est versionné.
- Sécurisé : redirection HTTPS globale, HSTS, en-têtes de sécurité, services privés inaccessibles depuis Internet.
Durcissement Docker autour du proxy
Le reverse proxy est le composant le plus exposé de la plateforme. C’est aussi celui qui a le plus de pouvoir, puisqu’il découvre les conteneurs via l’API Docker. D’où un durcissement spécifique :
- Socket Docker jamais monté directement. Traefik parle à un socket-proxy en lecture seule, qui ne laisse passer que les endpoints d’API strictement nécessaires à la découverte des services. Une compromission du proxy ne donne pas le contrôle du démon Docker.
no-new-privilegessur les conteneurs : pas d’escalade de privilèges possible via des binaires setuid.- Réseaux internes séparés. Le réseau du reverse proxy ne contient que les services à exposer. Les bases de données et services de support vivent dans des réseaux internes sans route vers l’edge.
Chaîne de middlewares (redirection, HSTS, exposition)
Les middlewares Traefik sont déclarés une fois puis composés par service :
- Redirection HTTPS globale : tout ce qui arrive en HTTP est redirigé, sans exception.
secure-headers: HSTS,X-Content-Type-Options: nosniff, protection contre l’embarquement en iframe, politique de referrer stricte.tailscale-only: les services privés n’acceptent que le réseau zero-trust. Le détail est sur la page Réseau zero-trust.
L’exposition d’un service se déclare ainsi route par route, jamais de façon implicite.