Partie 3 sur 7 — Supabase en auto-hébergement : retour d'expérience
Version française de Part 3 — Traefik and SSL.
Nous avons besoin d'un proxy inverse. Il se place devant tous nos conteneurs, effectue la terminaison TLS et achemine les requêtes entrantes vers le bon service en fonction du nom d'hôte. Traefik est le choix naturel pour les environnements Docker : il lit les labels des conteneurs et se configure automatiquement.
Ajoutez un label à un conteneur pour indiquer "je veux une route sur ce domaine" et Traefik la crée — élégant, mais un problème de compatibilité m'a rattrapé dès le départ et m'a coûté un bon moment.
Le problème de version
Les versions récentes de Docker Engine ont modifié la façon dont l'API négocie les versions avec les clients. Traefik v2, la version que l'on trouve dans la plupart des tutoriels, ne gère pas cela correctement. Il se connecte au daemon Docker, semble démarrer sans problème, mais échoue silencieusement à détecter les services.
Vos conteneurs tournent. Traefik tourne. Rien n'est routé. Aucun message d'erreur ne pointe clairement vers la cause.
La solution : passer à Traefik v3, la version majeure actuelle, qui gère correctement la négociation de version.
Si vous cherchez "Traefik Supabase Docker", la majorité des résultats montre encore une configuration Traefik v2. Gardez ça à l'esprit avant de copier quoi que ce soit.
Configuration DNS
Avant de configurer Traefik, vous devez créer des enregistrements DNS pointant vers votre serveur. Chez votre fournisseur DNS, créez des enregistrements A pour chaque sous-domaine que vous comptez utiliser :
kong.project1.yourdomain.com A YOUR_VPS_IP
studio.project1.yourdomain.com A YOUR_VPS_IP
kong.project2.yourdomain.com A YOUR_VPS_IP
studio.project2.yourdomain.com A YOUR_VPS_IP
Let's Encrypt vérifie ces enregistrements lors de l'émission des certificats. La propagation DNS prend généralement quelques minutes, mais peut aller jusqu'à quelques heures selon votre fournisseur. Avant de déployer, vérifiez que la propagation est complète. Si dig est disponible (apt install dnsutils -y), exécutez dig kong.project1.yourdomain.com +short et confirmez que votre IP VPS est bien retournée. Sinon, attendez et recommencez.
Le stack Traefik
Créez traefik/docker-compose.yml :
networks:
traefik_default:
driver: overlay
attachable: true
services:
traefik:
image: traefik:v3
command:
- "--providers.swarm.network=traefik_default"
- "--providers.swarm.exposedByDefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.le.acme.email=your@email.com"
- "--certificatesresolvers.le.acme.storage=/letsencrypt/acme.json"
- "--certificatesresolvers.le.acme.tlschallenge=true"
- "--log.level=INFO"
- "--api.dashboard=false"
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- letsencrypt:/letsencrypt
networks:
- traefik_default
deploy:
placement:
constraints:
- node.role == manager
volumes:
letsencrypt:
Quelques explications s'imposent.
exposedByDefault=false signifie que Traefik ignore tout conteneur qui ne s'inscrit pas explicitement avec traefik.enable=true. Sans ça, chaque conteneur sur le réseau Traefik serait accessible publiquement — autant dire une porte ouverte.
api.dashboard=false désactive l'interface web de Traefik. Le tableau de bord expose l'intégralité de votre configuration de routage : tous les noms de services, tous les domaines, tous les middlewares. Aucune raison d'exposer ça.
Le volume letsencrypt stocke les certificats. Ne le supprimez pas entre les déploiements. Let's Encrypt applique une limite de demandes de certificats par domaine et par semaine. Si vous videz le volume et redéployez à répétition, vous finirez par atteindre cette limite et vous ne pourrez plus obtenir de nouveau certificat pendant plusieurs jours.
Le trafic HTTP (port 80) est redirigé automatiquement vers HTTPS via les règles d'entrypoint.
Un problème de placement de labels
Dans un Docker Compose classique, les labels de service se placent au niveau du service :
services:
myapp:
labels:
traefik.enable: 'true'
Avec docker stack deploy en Docker Swarm, ils se placent dans le bloc deploy :
services:
myapp:
deploy:
labels:
traefik.enable: 'true'
Les labels placés au mauvais niveau sont ignorés silencieusement. Traefik ne routera pas le service et ne donnera aucune indication sur la raison. J'ai découvert ça à force de scruter une configuration d'apparence correcte, avant de finir par trouver l'erreur.
En-têtes de sécurité
Traefik propose un système de middlewares : des composants réutilisables qui traitent les requêtes avant qu'elles n'atteignent un service. Nous définissons un middleware security-headers qui ajoute HSTS, supprime l'en-tête Server, définit une politique de type de contenu, et ainsi de suite.
Dans Swarm, un middleware défini dans un stack est accessible aux autres stacks via le suffixe @swarm. Nous définissons le middleware des en-têtes dans les labels du stack project1 (présentés dans le billet suivant), et project2 y fait référence sous le nom security-headers@swarm. Traefik le détecte automatiquement dès que project1 est déployé.
Le middleware des en-têtes ressemble à ceci dans les labels du service :
traefik.http.middlewares.security-headers.headers.stsSeconds: '63072000'
traefik.http.middlewares.security-headers.headers.stsIncludeSubdomains: 'true'
traefik.http.middlewares.security-headers.headers.stsPreload: 'true'
traefik.http.middlewares.security-headers.headers.forceSTSHeader: 'true'
traefik.http.middlewares.security-headers.headers.contentTypeNosniff: 'true'
traefik.http.middlewares.security-headers.headers.referrerPolicy: strict-origin-when-cross-origin
traefik.http.middlewares.security-headers.headers.customFrameOptionsValue: SAMEORIGIN
traefik.http.middlewares.security-headers.headers.customResponseHeaders.Server: ''
Cette dernière ligne fixe l'en-tête de réponse Server à une chaîne vide. Par défaut, Kong annonce sa version dans chaque réponse — aucune raison de lui laisser ce plaisir.
Une remarque sur la dépendance inter-stacks : comme le middleware security-headers est défini dans le stack de project1, il disparaît si project1 est complètement arrêté — project2 se retrouverait alors sans middleware d'en-têtes. Pour un setup d'apprentissage, c'est acceptable ; la solution plus propre consiste à définir les middlewares partagés directement dans le stack Traefik.
Comment Kong obtient sa route
Seuls deux services de notre stack Supabase ont besoin d'une route publique : Kong (la passerelle API) et Studio (le tableau de bord). Tout le reste est interne.
Les labels du service Kong dans notre fichier Compose ressemblent à ceci :
services:
kong:
networks:
- internal
- traefik_default
deploy:
labels:
traefik.enable: 'true'
traefik.http.routers.p1-kong.entrypoints: websecure
traefik.http.routers.p1-kong.rule: Host(`kong.project1.yourdomain.com`)
traefik.http.routers.p1-kong.tls.certresolver: le
traefik.http.routers.p1-kong.middlewares: security-headers@swarm
traefik.http.services.p1-kong.loadbalancer.server.port: '8000'
traefik.swarm.network: traefik_default
Quelques subtilités à noter.
Le nom du routeur est p1-kong. Chaque nom de routeur doit être unique dans l'ensemble des stacks qui tournent dans Swarm. Si deux services enregistrent un routeur nommé kong, Traefik en choisit un et ignore l'autre sans avertissement. Nous préfixons avec l'identifiant du projet. C'est important dans le billet 6, quand nous ajoutons la deuxième instance.
Le label traefik.swarm.network indique à Traefik quel réseau utiliser pour acheminer les requêtes. Kong est connecté à deux réseaux : le réseau Supabase interne et le réseau Traefik. Sans ce label, Traefik pourrait essayer de passer par le réseau interne, qu'il ne peut pas atteindre.
Le loadbalancer.server.port indique à Traefik vers quel port transférer les requêtes à l'intérieur du conteneur. Comme nous ne publions pas le port de Kong vers l'hôte, Traefik a besoin de connaître directement le port du conteneur.
Déployer Traefik
docker stack deploy -c traefik/docker-compose.yml traefik
Vérifiez que le service a démarré :
docker service ls
# NAME MODE REPLICAS
# traefik_traefik replicated 1/1
Vérifier SSL plus tard
Après avoir déployé un projet Supabase dans le billet suivant, vérifiez que le certificat a bien été émis :
curl -I https://kong.project1.yourdomain.com/health
# HTTP/2 200
# strict-transport-security: max-age=63072000; includeSubDomains; preload
Et que l'en-tête Server a disparu de la réponse.
Alternatives à Traefik
Cette série utilise Traefik parce qu'il s'intègre naturellement à Docker Swarm via les labels de conteneurs. Supabase documente désormais officiellement Caddy et nginx comme alternatives plus simples — à consulter si vous préférez une configuration moins orientée labels.
Conformément au guide proxy officiel de Supabase, nous routons le trafic Storage directement vers le conteneur storage via Traefik, en contournant Kong. Kong ajoute une surcharge inutile pour les uploads et downloads de fichiers volumineux. Vous verrez les labels Traefik de Storage dans le fichier compose du prochain billet.
Partie 4 — La première instance Supabase →
La série complète
- Pourquoi auto-héberger
- Le serveur
- Traefik et SSL ← cet article
- La première instance Supabase
- Vault
- Deux instances
- Sécurité et test de charge
Top comments (0)