Auto-héberger Supabase sur un VPS avec Docker
Déployez la stack Docker officielle de Supabase sur votre serveur : secrets à remplacer, rôle des 14 services, mémoire requise, sauvegardes et mises à jour.
Ce que vous allez mettre en place
L’auto-hébergement de Supabase consiste à exécuter la stack officielle Docker Compose sur votre propre serveur : Postgres, une API REST devant la base de données, un service d’authentification, le stockage de fichiers, les websockets realtime et le tableau de bord Studio. Vous clonez un dépôt, modifiez un fichier .env, puis démarrez environ quatorze conteneurs qui fonctionnent ensemble comme un projet Supabase que vous contrôlez.
L’installation est rapide. Le principal point de défaillance est le fichier .env. Il contient des secrets de démonstration publiés dans le dépôt. Une stack démarrée avec ces valeurs par défaut est accessible à toute personne qui les découvre. Ce guide présente les secrets à remplacer, le rôle de chaque service, la quantité réelle de mémoire nécessaire à la stack et la manière de la mettre à jour sans supprimer votre base de données.
Si Compose est nouveau pour vous, consultez d’abord les bases de Docker Compose sur un VPS. Tout ce qui suit suppose que docker compose version affiche déjà une version.
Ce que contient réellement la stack
Supabase n'est pas un seul programme. Le fichier Compose démarre un ensemble de services distincts sur un même réseau. Savoir à quoi sert chacun permet de déboguer plus facilement une liste de noms de conteneurs.
dbest PostgreSQL avec les extensions Supabase chargées. Tous les autres services communiquent avec lui. Si ce conteneur est défaillant, tout le reste échoue également.kongest l'API gateway. Il écoute sur le port 8000 et achemine/rest/v1/,/auth/v1/et/storage/v1/vers le backend approprié. C'est le seul conteneur que vous devez exposer.restest PostgREST. Il lit le schéma Postgres et le fournit sous forme d'API REST. Une nouvelle table devient ainsi un nouvel endpoint, sans code supplémentaire.authest GoTrue. Il émet les JSON Web Tokens (JWT) qui identifient vos utilisateurs.storageetimgproxygèrent les téléversements de fichiers et le redimensionnement des images.realtimediffuse les modifications de la base de données via des websockets.studioetmetacorrespondent au dashboard et à l'API d'administration utilisée par celui-ci.analytics(Logflare) etvectorcollectent les logs, tandis quesupavisorest le pooler de connexions PostgreSQL.
Cette liste explique les valeurs de ressources indiquées plus loin. Vous n'exécutez pas seulement une base de données. Vous exécutez une base de données avec une douzaine de services auxiliaires.
Dimensionnement : prévoyez 8 GB de RAM
La stack utilise environ 2.5 à 3 GB de mémoire résidente au repos après une installation fraîche, en juillet 2026, avant l’ajout de vos propres données ou du trafic réseau. Le service d’analytics et le processus Node.js de Studio sont les deux plus gros consommateurs individuels. Un serveur de 2 GB démarre les conteneurs, puis le kernel en arrête un avec l’out-of-memory killer, généralement analytics ou db. Le symptôme est un conteneur qui redémarre en boucle avec le code de sortie 137.
Prévoyez 8 GB de RAM et 4 vCPU pour toute instance dont vous dépendez. 4 GB suffisent pour une instance de développement individuelle si vous acceptez qu’une requête lourde exécutée en même temps qu’une session Studio soit lente. Le disque compte également, car Postgres, le volume de stockage et les données de log se trouvent tous dans le répertoire du projet. Commencez avec 40 GB et surveillez l’utilisation.
Installation : cloner le dépôt officiel
La procédure prise en charge consiste à copier le répertoire docker depuis le dépôt principal vers votre propre répertoire de projet. Cette séparation est importante, car elle empêche un git pull ultérieur d’écraser votre .env.
git clone --depth 1 https://github.com/supabase/supabase
mkdir supabase-project
cp -rf supabase/docker/* supabase-project
cp supabase/docker/.env.example supabase-project/.env
cd supabase-project
docker compose pulldocker compose pull télécharge plusieurs gigaoctets d’images. La commande doit se terminer avec tous les services marqués Pulled. Une erreur manifest unknown à ce stade signifie que le tag d’image épinglé a été supprimé en amont. Pour corriger le problème, récupérez une version plus récente du dépôt au lieu de modifier manuellement les tags.
Les secrets que vous devez modifier avant le premier démarrage
Faites-le avant de démarrer la stack, et non après. Plusieurs de ces valeurs sont écrites dans les données au premier démarrage. Les modifier ensuite impose donc de réinitialiser la base de données.
Le dépôt fournit un générateur qui produit correctement toutes les valeurs, y compris les deux clés d’API qui doivent être signées avec votre nouveau secret JWT.
sh utils/generate-keys.sh --update-envCe script écrit de nouvelles valeurs pour JWT_SECRET, ANON_KEY, SERVICE_ROLE_KEY, SECRET_KEY_BASE, REALTIME_DB_ENC_KEY, VAULT_ENC_KEY, PG_META_CRYPTO_KEY et les tokens Logflare dans .env. Il nécessite openssl, présent dans toute image Ubuntu standard.
Il ne définit pas deux valeurs. Vous devez les modifier manuellement dans .env :
POSTGRES_PASSWORD. Utilisez uniquement des lettres et des chiffres. La ponctuation casse les chaînes de connexion que plusieurs services construisent en concaténant des chaînes. L’échec ressemble alors à une erreur d’authentification plutôt qu’à une erreur d’analyse syntaxique, ce qui oriente les recherches au mauvais endroit.DASHBOARD_USERNAMEetDASHBOARD_PASSWORD. Il s’agit des identifiants d’authentification Basic de Studio. Le mot de passe par défaut fourni est littéralementthis_password_is_insecure_and_should_be_updated.
Comprenez pourquoi ANON_KEY et SERVICE_ROLE_KEY ne peuvent pas être inventés. Ce sont tous les deux des JWT signés avec JWT_SECRET. La gateway vérifie cette signature sur chaque requête. Une clé qui ne correspond pas à votre secret est donc rejetée avec {"message":"Invalid authentication credentials"}. C’est l’échec le plus courant lors d’un self-hosting : l’opérateur modifie JWT_SECRET, mais conserve les clés de démonstration. Générez toujours les trois ensemble.
Traitez SERVICE_ROLE_KEY comme un mot de passe root. Il contourne complètement la sécurité au niveau des lignes. Il doit figurer dans le code côté serveur, et nulle part ailleurs.
Définissez SITE_URL et API_EXTERNAL_URL sur l’adresse que vos utilisateurs utiliseront réellement, par exemple https://supabase.example.com. Auth construit les liens de confirmation par e-mail et les liens de callback OAuth à partir de ces valeurs. Si vous les laissez sur http://localhost:8000, tous vos utilisateurs seront redirigés vers leur propre machine.
Vérifiez ensuite les valeurs obtenues :
sh run.sh secretsDémarrez-le et vérifiez qu’il fonctionne correctement
sh run.sh start
docker compose psrun.sh start encapsule docker compose up -d --wait. Il ne renvoie donc la main qu’une fois les contrôles de santé réussis. Chaque service doit afficher running (healthy) ou running. Le premier démarrage prend de deux à quatre minutes, car Postgres exécute ses scripts d’initialisation avant que toute autre connexion soit possible.
Si un conteneur redémarre, consultez ses logs à l’aide du nom du service :
docker compose logs db
docker compose logs authStudio écoute ensuite sur le port 8000 et demande le nom d’utilisateur et le mot de passe du dashboard que vous avez définis.
N’exposez pas le port 8000 sur Internet
Kong sur le port 8000 utilise HTTP en clair. Chaque clé d’API et chaque mot de passe utilisateur transitent sur le réseau en clair. Les identifiants de Studio utilisent l’authentification de base, qui repose sur un encodage base64 et non sur le chiffrement.
Placez un reverse proxy devant Kong et terminez TLS (transport layer security) à cet endroit. Liez Kong à l’adresse de loopback afin qu’aucun autre service ne puisse y accéder. Dans docker-compose.yml, le mapping de ports kong devient 127.0.0.1:8000:8000, et le proxy redirige les requêtes vers ce port. La page Traefik devant plusieurs applications Compose explique la configuration des certificats.
Fermez également les autres ports au niveau du pare-feu. Docker publie les ports en ajoutant ses propres règles iptables, que la configuration naïve de ufw ne prend jamais en compte. Ce piège est expliqué dans pourquoi les conteneurs Docker ignorent vos règles ufw.
Sauvegardez la base de données, pas le répertoire
Les données Postgres se trouvent dans un bind mount à ./volumes/db/data. Copier ce répertoire pendant l’exécution du conteneur produit une copie incohérente, car Postgres met les écritures en mémoire tampon et les fichiers sur le disque ne sont cohérents qu’au moment d’un checkpoint. La restauration fonctionnera généralement, mais certaines transactions récentes pourront être perdues sans message d’erreur. C’est le pire mode d’échec possible pour une sauvegarde.
Utilisez plutôt un dump. pg_dumpall s’exécute dans le conteneur et produit un instantané cohérent :
docker exec -t supabase-db pg_dumpall -U postgres > supabase-$(date +%F).sqlVérifiez que le fichier n’est pas vide avant de lui faire confiance. Transférez ensuite régulièrement ces dumps hors du serveur. C’est le rôle de sauvegardes chiffrées hors site avec restic. Sauvegardez également votre .env au même moment. La perte de JWT_SECRET invalide tous les tokens émis et rend tous les secrets chiffrés stockés illisibles.
Les fichiers téléversés se trouvent dans ./volumes/storage. Ce sont des fichiers ordinaires, donc une simple copie suffit.
Mettre à jour sans perdre de données
Supabase verrouille les versions des images dans docker-compose.yml. Rien ne change tant que vous ne lancez pas la mise à jour. Effectuez toujours un dump au préalable.
docker compose pull
sh run.sh recreaterecreate arrête la stack, puis la redémarre avec les nouvelles images. Vos données sont conservées, car elles résident dans les bind mounts sur l’hôte, et non dans les conteneurs. Consultez CHANGELOG.md dans le repository avant tout changement de version majeure, car les mises à niveau majeures de Postgres ne sont pas automatiques et nécessitent un dump, puis une restauration.
Pour appliquer les modifications du fichier Compose lui-même, clonez de nouveau le repository en amont et copiez son répertoire docker dans votre projet. Veillez à ne pas écraser .env.
La réinitialisation complète, qui détruit tout, y compris la base de données, utilise un script distinct et demande une confirmation :
sh reset.shFAQ
Pourquoi mes appels API renvoient-ils « Invalid authentication credentials » ?
Votre ANON_KEY ou votre SERVICE_ROLE_KEY n’a pas été signé avec le JWT_SECRET actuellement défini dans .env. La gateway vérifie la signature de chaque requête et rejette toute discordance. Régénérez les trois valeurs ensemble avec sh utils/generate-keys.sh --update-env, puis exécutez sh run.sh recreate afin que les services chargent les nouvelles valeurs.
Puis-je exécuter Supabase auto-hébergé sur un VPS de 2 GB ?
Pas de manière fiable. La stack utilise près de 3 GB au repos en juillet 2026, car elle exécute environ quatorze services. Un serveur de 2 GB perd donc des containers à cause de l’out of memory killer, et vous voyez le code de sortie 137 dans docker compose ps. Utilisez 8 GB en production et considérez 4 GB comme le minimum pour le développement individuel.
Supabase auto-hébergé inclut-il les edge functions ?
Oui. Le fichier Compose inclut le runtime de fonctions basé sur Deno et sert tout ce que vous placez sous ./volumes/functions. Il n’inclut pas le réseau de déploiement global de la plateforme hébergée. Vos fonctions s’exécutent donc sur votre unique serveur, dans un seul emplacement.
Comment me connecter directement à la base de données Postgres ?
Utilisez docker exec -it supabase-db psql -U postgres pour ouvrir un shell interactif directement sur le serveur. Depuis un client externe, connectez-vous à Supavisor sur le port 5432 avec l’utilisateur postgres.<POOLER_TENANT_ID> et votre POSTGRES_PASSWORD. N’exposez pas ce port sur Internet. Accédez-y via un VPN ou un tunnel SSH.
Pourquoi les e-mails de confirmation de mon service d’authentification contenaient-ils un lien vers localhost ?
SITE_URL et API_EXTERNAL_URL dans .env avaient conservé leurs valeurs par défaut. Le service d’authentification construit chaque lien de confirmation et de réinitialisation du mot de passe à partir de ces deux valeurs. Il envoie donc l’adresse qui lui a été configurée. Définissez les deux valeurs avec votre URL publique réelle, puis recréez la stack.