Aller au contenu
Sylvain Joffraud l4w
Retour

Supabase self-hosted : le Studio exposé via l’API Kong

Sur un Supabase self-hosted, le Studio exposé via Kong est une deuxième porte d’entrée qu’on oublie : j’avais protégé le vhost dédié du Studio, mais l’hôte de l’API Kong sert lui aussi le Studio sur /, avec en prime /pg/ (postgres-meta) et /mcp. Le Studio n’a pas d’authentification propre : c’est un accès admin complet à la base, SQL Editor compris. Le correctif tient en un snippet Apache qui ne laisse publics sur l’hôte API que les préfixes utilisés par les applications, et réserve tout le reste au mesh WireGuard d’administration.

Le setup : deux vhosts Apache devant Coolify

L’instance tourne sur srv-a, déployée par Coolify v4 (une douzaine de conteneurs : db, kong, auth, rest, realtime, storage, studio, meta…). Apache est en frontal, Traefik derrière :

https://supabase.dev.example.com      → Apache:443 → Traefik:8443 → supabase-studio:3000
https://api.supabase.dev.example.com  → Apache:443 → Traefik:8443 → supabase-kong:8000

Ces deux noms sont d’ailleurs ceux qui avaient cessé de résoudre à cause d’un TXT _acme-challenge oublié qui cassait le wildcard DNS.

Jusqu’au 25 septembre 2026, la règle était : tout Studio Supabase derrière une Basic Auth Apache, sur un vhost avec ServerName exact pour primer sur le catch-all *.dev.example.com (qui, lui, ne filtre rien). Ce matin-là, j’ajoute une deuxième instance avec le même modèle. Et la règle avait une exception explicite : pas de Basic Auth sur l’API Kong, puisque les applications s’y authentifient avec leur apikey.

Pourquoi l’hôte API sert-il le Studio ?

Kong est la gateway de Supabase : elle route /auth/v1/ vers GoTrue, /rest/v1/ vers PostgREST, /storage/v1/ vers le stockage, etc. Mais la configuration Kong du déploiement contient aussi une route dashboard sur /, qui renvoie vers le Studio, protégée par la Basic Auth de Kong (realm="service", identifiants DASHBOARD_USERNAME / DASHBOARD_PASSWORD).

Résultat : mon vhost Studio était verrouillé, mais https://api.supabase.dev.example.com/ affichait le même Studio derrière un simple mot de passe, exposé à Internet. Même chose pour /pg/, l’API postgres-meta, l’interface REST de gestion de Postgres sur laquelle s’appuie le Studio, et pour /mcp.

Protéger le vhost d’une interface d’admin ne sert à rien si la gateway de l’API la republie sur un autre nom : il faut auditer chaque hôte, pas chaque application.

La fausse piste : une Basic Auth devant Kong

Première idée : mettre la Basic Auth Apache sur l’hôte API aussi. Impossible : les clients supabase-js appellent cet hôte depuis le navigateur et les serveurs avec leur apikey, une authentification Apache globale les casserait tous. Il fallait raisonner par chemin, pas par hôte.

J’en ai profité pour abandonner aussi la Basic Auth sur le Studio : un mot de passe devant un accès complet à la base, c’est mince. Les Studios sont désormais réservés aux deux postes admin du mesh WireGuard (10.8.0.2 en split-tunnel, 10.8.0.3 en full-tunnel). Les autres machines du mesh (srv-b, nas, pc-llm…) sont exclues exprès.

Le correctif : filtrer l’API Kong par préfixe

Deux snippets Apache sur srv-a portent la règle, pour qu’elle ne vive qu’à un seul endroit. Celui du Studio est un Require ip inclus dans le <Location /> du vhost :

# /etc/apache2/supabase-acl-studio.conf
Require ip 10.8.0.2 10.8.0.3

Celui de l’hôte API, inclus juste après le ServerName, ferme tout l’hôte au mesh puis rouvre une liste blanche de préfixes :

# /etc/apache2/supabase-acl-api.conf
<Location />
    Include /etc/apache2/supabase-acl-studio.conf
</Location>
<LocationMatch "^/((auth|rest|realtime|storage|functions)/v1/|graphql/v1|sso/saml/|\.well-known/oauth-authorization-server)">
    Require all granted
</LocationMatch>

Pas de lookahead négatif à maintenir : Apache fusionne les sections <LocationMatch> après les <Location>, donc son Require all granted l’emporte sur les préfixes publics. Le / de Kong, /pg/ et /mcp restent sous le Require ip du Studio.

Chemin sur l’hôte APIAccès
/auth/v1/, /rest/v1/, /realtime/v1/, /storage/v1/, /functions/v1/public
/graphql/v1, /sso/saml/, /.well-known/oauth-authorization-serverpublic
/ (Studio via la route dashboard), /pg/, /mcp, tout le restemesh admin

Chaque instance Supabase a donc besoin de deux vhosts dédiés, un pour le Studio et un pour l’API, puis sudo apache2ctl configtest && sudo systemctl reload apache2. Le poste en split-tunnel demande en plus une résolution DNS du nom du Studio vers l’IP mesh, sinon la requête sort par la box et prend un 403.

Vérifier depuis Internet et depuis le tunnel

Le test qui compte se fait des deux côtés :

curl -so/dev/null -w '%{http_code}' https://supabase.dev.example.com/
# depuis Internet : 403
# tunnel WireGuard monté : 307

Le même test sur https://api.supabase.dev.example.com/ doit lui aussi renvoyer 403 depuis Internet, tandis qu’un appel applicatif sur /rest/v1/ doit continuer de passer. Le fichier htpasswd de l’ancienne Basic Auth n’est plus utilisé ; je l’ai gardé pour un éventuel retour arrière.

Lessons learned

Questions fréquentes

Pourquoi le Studio Supabase est-il accessible depuis l’URL de l’API ?
Sur un Supabase self-hosted, la gateway Kong porte une route dashboard qui sert le Studio sur / de l’hôte API, derrière une Basic Auth Kong (realm="service"). Restreindre le vhost dédié au Studio ne ferme donc pas cette deuxième porte : l’hôte API publie aussi /pg/ (postgres-meta) et /mcp.
Peut-on mettre une Basic Auth Apache devant l’API Kong de Supabase ?
Non, pas devant toute l’API Kong : les applications clientes s’y authentifient avec leur clé apikey, et une Basic Auth globale les bloquerait. La bonne approche consiste à laisser publics uniquement les préfixes dont les clients ont besoin (/auth/v1/, /rest/v1/, /storage/v1/…) et à réserver tout le reste à un réseau d’administration.
Quels chemins de l’API Supabase doivent rester publics ?
Dans mon installation Supabase self-hosted, la liste blanche publique contient /auth/v1/, /rest/v1/, /realtime/v1/, /storage/v1/, /functions/v1/, /graphql/v1, /sso/saml/ et /.well-known/oauth-authorization-server. Tout autre chemin de l’hôte API, dont /, /pg/ et /mcp, est réservé au mesh WireGuard. Cette liste couvre les services appelés par supabase-js : authentification, PostgREST, temps réel, stockage et Edge Functions.
Comment vérifier que le Studio Supabase n’est plus joignable depuis Internet ?
Un simple curl -so/dev/null -w '%{http_code}' sur l’URL du Studio suffit : depuis Internet, la réponse attendue est 403 ; depuis un poste admin avec le tunnel WireGuard monté, le Studio répond 307, sa redirection habituelle. Il faut faire le même test sur / de l’hôte API, pas seulement sur le vhost du Studio.

Partager cet article :

Article précédent
Ollama : l’heure en tête du prompt casse le cache
Article suivant
Suppression de compte RGPD : le piège ON DELETE CASCADE