Pourquoi auto-héberger Supabase sur un VPS
Supabase n'est pas une boîte noire : c'est un ensemble de services open source (PostgreSQL, GoTrue pour l'auth, PostgREST pour l'API, Realtime, Storage, Kong en gateway) orchestrés ensemble. La version cloud facture par projet et par utilisateur actif, et met en pause les projets gratuits inactifs. En self-hostant sur un VPS, vous obtenez un backend-as-a-service complet sans ces limites, avec un accès direct à votre PostgreSQL pour les migrations, les extensions (pgvector, PostGIS) et le tuning. C'est idéal pour une agence qui héberge plusieurs apps clientes, un SaaS en démarrage qui veut maîtriser ses coûts, ou tout projet exigeant la souveraineté des données. Vous gérez vous-même les mises à jour et la sauvegarde, en échange d'une liberté totale.
Les bénéfices concrets d'un Supabase auto-hébergé
- Backend complet : base Postgres, Auth, Storage, Realtime et API REST/GraphQL en une stack.
- Accès direct au PostgreSQL sous-jacent : migrations SQL, extensions et politiques RLS sans limite.
- Pas de mise en pause ni de facturation par utilisateur actif mensuel.
- Studio inclus : interface d'administration web pour gérer tables, auth et buckets.
- Extensions IA via
pgvectorpour le RAG et la recherche sémantique, activées librement. - Multi-projets sur un même VPS : pratique pour une agence ou un studio de développement.
Prérequis matériels et logiciels
Supabase self-hosted lance une dizaine de conteneurs (Postgres, Kong, GoTrue, PostgREST, Realtime, Storage, Studio, Meta, Imgproxy...), c'est donc une stack plus gourmande qu'une simple base. Comptez un minimum de 2 vCPU et 4 Go de RAM pour un environnement de test, et plutôt 4 vCPU avec 8 Go de RAM et 80 Go de SSD pour de la production. Côté logiciel : Ubuntu 22.04/24.04 LTS, Docker et Docker Compose v2, un nom de domaine pointant vers le VPS (ex : api.monsaas.com) pour exposer la gateway en HTTPS, et un reverse proxy comme Caddy, Traefik ou Nginx pour gérer le SSL. Prévoyez aussi de générer des secrets robustes (JWT_SECRET, clés anon et service_role).
Déployer Supabase self-hosted avec Docker
Cloner le dépôt officiel et préparer l'environnement
Récupérez le dossier
dockerdu dépôt Supabase, copiez.env.exampleen.env, puis générez des secrets uniques :POSTGRES_PASSWORD,JWT_SECRET, et les clésANON_KEY/SERVICE_ROLE_KEYdérivées du JWT. Ne déployez jamais avec les valeurs d'exemple.Configurer les URLs et le mot de passe Studio
Dans
.env, définissezSITE_URL,API_EXTERNAL_URLetSUPABASE_PUBLIC_URLavec votre domaine, et protégez Supabase Studio avecDASHBOARD_USERNAMEetDASHBOARD_PASSWORD: le Studio donne un accès admin total à votre projet.Lancer la stack
Démarrez avec
docker compose up -d, puis suivez le démarrage des services viadocker compose ps. La première initialisation de Postgres et l'application des migrations internes prennent une à deux minutes ; vérifiez l'absence d'erreurs dansdocker compose logs.Placer un reverse proxy avec SSL
Mettez Caddy ou Traefik devant Kong (le port 8000 de la gateway) pour exposer votre API en HTTPS. Caddy obtient et renouvelle automatiquement les certificats Let's Encrypt : un simple bloc
monsaas.com { reverse_proxy localhost:8000 }suffit. N'exposez jamais Postgres (5432) publiquement.Activer les politiques RLS
Connectez-vous au Studio, créez vos tables, puis activez Row Level Security sur chacune et définissez vos policies. Sans RLS, votre clé
anonexpose toutes vos données : c'est le réglage à faire avant d'exposer quoi que ce soit.Sauvegarder Postgres et le Storage
Planifiez un
pg_dumpquotidien de la base et archivez le volume de Storage (buckets de fichiers) vers un stockage externe. Testez la restauration complète sur un VPS de staging avant de compter dessus en production.
Supabase vs Appwrite : quel BaaS self-hosted choisir ?
Faites défiler le tableau
| Critère | Supabase | Appwrite |
|---|---|---|
| Base de données | PostgreSQL natif, SQL complet | MariaDB en interne, API document/collection |
| Modèle de données | Relationnel, RLS Postgres | Documents et collections, permissions par règle |
| API auto-générée | REST (PostgREST) + GraphQL | REST, GraphQL et SDK multiples |
| Authentification | GoTrue, OAuth, magic links | Auth intégrée, OAuth, équipes, JWT |
| Empreinte ressources | Plus lourde (~10 conteneurs) | Modérée, stack plus compacte |
| Recherche vectorielle / IA | Native via pgvector | Non native, à externaliser |
| Idéal pour | Apps relationnelles, RAG, SQL avancé | Apps mobiles/web orientées documents |
| Courbe d'apprentissage | Confortable si vous connaissez SQL | Rapide pour les développeurs front/mobile |
Mettez à jour Supabase avec prudence : les images étant versionnées dans le docker-compose.yml, faites toujours un pg_dump complet et un snapshot du VPS avant un docker compose pull && docker compose up -d. Certaines montées de version touchent au schéma interne des services. Pour la production, isolez Postgres sur un volume dédié à fort IOPS et activez pgvector dès le départ si vous prévoyez de la recherche sémantique : l'ajouter plus tard impose une migration de schéma.
Déployez à partir de la stack officielle de Supabase, pas d'un compose fait maison
Il est tentant d'écrire un docker-compose minimal avec seulement les quelques services dont vous avez besoin. En pratique, cela casse : l'image supabase/postgres exécute son propre script de migration (migrate.sh) qui provisionne les rôles de base (supabase_admin, authenticator, supabase_auth_admin...) et l'intégralité du schéma d'authentification, et elle attend la présence des fichiers SQL d'initialisation de Supabase montés comme fichiers, avec expansion des variables à l'exécution. Un compose inline autonome ne peut pas reproduire cela (Docker Compose interpole les variables à l'intérieur des configurations inline, laissant le schéma d'authentification à moitié migré et GoTrue échouer avec 'must be owner of function auth.uid()'). L'approche robuste — celle qu'utilise ServOrbit — consiste à déployer les fichiers Docker officiels de Supabase, figés sur une version précise, et à laisser son migrate.sh faire l'amorçage exactement comme le prévoit l'upstream.
Sauvegarder automatiquement votre instance
Le déploiement Docker de Supabase ne sauvegarde rien tout seul : c'est le manque le plus souvent signalé par ceux qui l'auto-hébergent. Deux mécanismes se complètent. Le premier, pg_dump, produit une copie logique complète — lancez-le par cron depuis l'hôte, vers un volume distinct de celui de la base, et conservez plusieurs générations. Le second, l'archivage WAL, journalise chaque transaction et permet de remonter à un instant précis plutôt qu'au dernier dump. Le premier suffit à la plupart des projets ; le second devient nécessaire dès que perdre une journée d'écritures n'est pas acceptable. Dans les deux cas, la sauvegarde ne vaut que si vous avez déjà restauré une fois : montez une instance vierge et rejouez votre dump dedans avant d'en avoir besoin.
Alléger la stack : le service analytics
La composition Docker officielle embarque Logflare, le service d'analytique interne de Supabase, sous le nom analytics. Il n'est indispensable ni à l'API, ni à l'authentification, ni au stockage : c'est un outil d'observabilité. Sur un VPS aux ressources comptées, il est fréquent de le voir remonter en état unhealthy sans que le reste de la pile en souffre, et beaucoup d'auto-hébergeurs finissent par le commenter dans leur docker-compose.yml. Mesurez d'abord ce qu'il consomme chez vous avec docker stats avant de décider : si votre supervision passe déjà par un outil externe, vous n'y perdez rien ; si vous comptiez sur ses journaux, coupez-le seulement après avoir branché un remplaçant.
Migration Kong→Envoy : ce qui change, et pour qui c'est cassant
La semaine du 9 août 2026, Supabase a fait d'Envoy la passerelle API par défaut des installations self-hosted ; Kong passe en surcouche optionnelle. Envoy était déjà disponible depuis plusieurs versions via docker-compose.envoy.yml — c'est le défaut qui change.
Dans docker-compose.yml, le service s'appelle désormais api-gw et le conteneur supabase-envoy, mais l'alias réseau kong est conservé : les services qui appellent la passerelle par ce nom continuent de fonctionner. Le port HTTP reste 8000, réglable par API_GW_HTTP_PORT, donc votre reverse proxy Caddy ou Nginx n'a rien à changer.
⚠️ L'éditeur qualifie ce changement de cassant pour une PARTIE des auto-hébergeurs, et il faut savoir si vous en êtes. Trois cas : vous vous appuyiez sur le port HTTPS 8443 intégré à Kong — il n'est plus fourni par défaut, la terminaison TLS passe par docker-compose.caddy.yml ou docker-compose.nginx.yml ; vous aviez un volumes/api/kong.yml personnalisé — routes et plugins sont à porter vers la configuration Envoy, qui vit dans volumes/api/envoy/ ; vos scripts désignent la passerelle par son nom de service. Dans les trois cas, vous pouvez aussi rester sur Kong : sh run.sh config add kong.
Passer à Envoy sans casser votre passerelle
Savoir sur quoi vous tournez
Lancez
docker compose ps. Un conteneursupabase-kongsignifie que vous êtes encore sur Kong ;supabase-envoyque la bascule est faite. Vérifiez aussi la présence d'unvolumes/api/kong.ymlmodifié par rapport à celui du dépôt — c'est lui qui décide si la migration vous coûte du travail.Sauvegarder avant de toucher au compose
Faites un
pg_dumpcomplet et, si votre hébergeur le permet, un snapshot du VPS. La bascule de passerelle ne touche pas au schéma PostgreSQL, mais elle change le chemin d'entrée de toutes vos requêtes : un retour arrière rapide vaut mieux qu'un diagnostic à chaud.Décider : porter ou rester
Si votre
kong.ymlest celui du dépôt, il n'y a rien à porter. S'il contient des routes ou des plugins à vous, deux voies : les traduire en configuration Envoy sousvolumes/api/envoy/, ou rester sur Kong avecsh run.sh config add kongle temps de le faire. Rester est une décision légitime, pas un échec.Récupérer le nouveau compose et redémarrer
Tirez la dernière version du dossier
dockerdu dépôt officiel Supabase, puisdocker compose down && docker compose up -d. Vérifiez queapi-gwpasse enhealthyet que l'API répond sur le port 8000.Rétablir le TLS si vous passiez par le 8443 de Kong
Le port HTTPS intégré n'est plus fourni. Ajoutez la terminaison TLS avec
docker-compose.caddy.ymloudocker-compose.nginx.yml, ou laissez votre reverse proxy existant s'en charger devant le port 8000. C'est le point qui casse le plus souvent, et il ne se voit qu'au premier appel HTTPS direct.Vérifier le stockage et les URL signées
Testez un téléchargement depuis un bucket privé via une URL pré-signée. Si vous obtenez un 403 après la bascule, regardez d'abord la réécriture de l'en-tête
Hostet la valeur de l'URL publique de votre service de stockage : c'est là que se logent les écarts entre les deux passerelles.
Kong et Envoy, point par point
Faites défiler le tableau
| Aspect | Kong (avant août 2026) | Envoy (par défaut depuis) |
|---|---|---|
| Service dans `docker-compose.yml` | `kong` | `api-gw` — alias réseau `kong` conservé |
| Conteneur | `supabase-kong` | `supabase-envoy` |
| Port HTTP | 8000 | 8000 — via `API_GW_HTTP_PORT` |
| Port HTTPS intégré | 8443 | **retiré** — TLS par `docker-compose.caddy.yml` / `.nginx.yml` |
| Configuration | `volumes/api/kong.yml` | `volumes/api/envoy/` (YAML versionné) |
| Revenir en arrière | — | `sh run.sh config add kong` |
CVE-2026-31813 : faille OIDC dans GoTrue — mettez à jour
Une vulnérabilité a été divulguée en 2026 dans GoTrue (le service d'authentification de Supabase) sous la référence CVE-2026-31813. La faille se situe dans la validation du claim iss lors de l'authentification OIDC : un token JWT signé par un fournisseur d'identité tiers (Apple ou Azure) mais avec un iss différent de celui configuré dans GoTrue était accepté dans certaines conditions de configuration.
En pratique, un attaquant qui contrôle un fournisseur OIDC enregistré dans l'application cliente peut émettre des tokens valides pour des utilisateurs arbitraires de votre instance Supabase. La portée réelle dépend de la configuration : seules les instances avec au moins un fournisseur OAuth tiers activé (Social Auth) sont concernées. Les instances qui utilisent uniquement l'authentification email/mot de passe ou les magic links ne sont pas exposées.
Le correctif est inclus dans Supabase Auth (GoTrue) 2.185.0. Pour vérifier votre version : docker compose exec auth gotrue version. Si votre version de gotrue est antérieure à 2.185.0, mettez à jour immédiatement.
Mettre à jour GoTrue pour corriger CVE-2026-31813
Identifier la version en cours
Depuis le répertoire de votre stack Supabase :
docker compose exec auth gotrue version. Si la sortie indique une version < 2.185.0, votre instance est exposée au CVE-2026-31813. Notez également la version globale de la stack :grep 'SUPABASE_VERSION' .env(si vous l'avez épinglée) oudocker compose images | grep supabase.Sauvegarder avant la mise à jour
Avant toute mise à jour, sauvegardez la base :
docker compose exec db pg_dumpall -U postgres > /tmp/supabase-backup-$(date +%F).sql. La mise à jour de GoTrue n'implique pas de migration de schéma PostgreSQL, mais une sauvegarde préalable reste la règle avant tout changement de version en production.Mettre à jour Supabase Auth vers 2.185.0 ou plus récent
Dans votre
docker-compose.yml, mettez à jour le tag de l'imagesupabase/gotrueversv2.185.0ou plus récent, ou si vous suivez la stack globale, tirez la dernière version compatible :docker compose pull && docker compose up -d auth. La mise à jour de GoTrue seul ne nécessite pas de redémarrer les autres services. Vérifiez avecdocker compose exec auth gotrue versionque la nouvelle version est active.Vérifier l'authentification OIDC
Après la mise à jour, testez un flux d'authentification complet avec chaque fournisseur OIDC configuré : connexion, déconnexion, reconnexion. Vérifiez dans les logs GoTrue (
docker compose logs auth) qu'aucun message d'erreur relatif à la validationissn'apparaît en conditions normales d'utilisation.
Si une mise à jour immédiate n'est pas possible (fenêtre de maintenance requise), vous pouvez réduire la surface d'exposition en désactivant temporairement les fournisseurs OAuth tiers dans le Studio Supabase : Authentication → Providers, puis désactivez chaque fournisseur Social. L'authentification email/mot de passe reste fonctionnelle. Ce contournement est temporaire : il ne corrige pas la faille, il réduit seulement la surface d'attaque pendant que vous préparez la mise à jour.
Migration PostgreSQL 15 → 17 : ne tirez pas avant d'épingler
En juin 2026, Supabase a changé l'image PostgreSQL par défaut de la version 15 à la version 17 dans son docker-compose.yml officiel (changelog du 2026-05-18, effectif à partir du 2026-06-17). Ce changement est silencieux et destructeur si vous l'ignorez : PostgreSQL 17 ne peut pas lire un volume de données créé par PostgreSQL 15, et refuse de démarrer. Un simple docker compose pull sans avoir épinglé l'image supabase/postgres vous brique l'instance — la discussion [#46080](https://github.com/orgs/supabase/discussions/46080) ouverte en mai 2026 a rassemblé des centaines de signalements.
Deuxième piège : les extensions timescaledb, plv8, plcoffee et plls ont été retirées de l'image PG 17 officielle. Si votre base les utilise, la migration exige de les réinstaller depuis des dépôts communautaires, ou de renoncer à la montée de version. Vérifiez avant d'aller plus loin : docker compose exec db psql -U postgres -c "\dx" liste les extensions actives.
Migrer de PostgreSQL 15 vers 17 sans perdre vos données
Épingler l'image PG 15 avant tout `docker compose pull`
Ouvrez votre
docker-compose.ymlet trouvez la ligne de l'image du servicedb. Remplacezsupabase/postgres:latest(ou tout tag flottant) par un tag de version fixe PG 15, par exemplesupabase/postgres:15.8.1.060. Vérifiez la dernière version 15 disponible sur le Docker Hub de Supabase. Tant que ce tag est épinglé, undocker compose pullne changera rien à votre base.Dump complet de la base PostgreSQL 15
Depuis l'hôte, exportez la totalité de vos données avec
pg_dumpall:docker compose exec db pg_dumpall -U postgres > supabase-pg15-dump-$(date +%F).sql. Ce fichier contient rôles, schémas et données. Vérifiez qu'il n'est pas vide et qu'il se termine par-- PostgreSQL database cluster dump complete. Conservez-le sur un volume distinct du VPS et sur un stockage externe.Arrêter la stack et supprimer le volume de données PG 15
Arrêtez tous les services :
docker compose down. Identifiez le volume de la base avecdocker volume ls | grep supabase. Avant de le supprimer, assurez-vous que votre dump est complet et lisible. Puis supprimez le volume de données Postgres uniquement :docker volume rm <nom_du_volume_postgres>. Ne supprimez pas les volumes de Storage ni d'autres services.Passer à l'image PostgreSQL 17 dans docker-compose.yml
Modifiez la ligne de l'image du service
dbpour pointer vers PostgreSQL 17, par exemplesupabase/postgres:17.4.1.060(vérifiez la dernière version 17 disponible sur Docker Hub). Vérifiez également les variables d'environnement et de santé du service — l'image PG 17 peut avoir des chemins ou des paramètres légèrement différents de PG 15.Démarrer le conteneur PG 17 vide et restaurer le dump
Démarrez uniquement le service de base de données :
docker compose up -d db. Attendez qu'il passe en étathealthy(docker compose ps). Puis restaurez l'export :docker compose exec -T db psql -U postgres -f /dev/stdin < supabase-pg15-dump-$(date +%F).sql. La restauration prend quelques minutes selon le volume de données ; des messages d'avertissement sur des rôles existants sont normaux.Vérifier les extensions et redémarrer la stack complète
Avant de relancer tous les services, vérifiez les extensions :
docker compose exec db psql -U postgres -c "\dx". Sitimescaledb,plv8,plcoffeeoupllsétaient présentes en PG 15, elles n'existent plus dans l'image PG 17 officielle — installez-les depuis leurs dépôts communautaires respectifs, ou retirez les références dans votre schéma. Une fois prêt, démarrez la stack complète :docker compose up -d. Vérifiez chaque service avecdocker compose pset testez un appel API complet avant de considérer la migration terminée.