Installer Supabase en self-hosting sur un VPS Docker
Déployez la stack Docker officielle de Supabase sur votre VPS : secrets à remplacer, rôle des 14 services, RAM 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 celui-ci, un service d’authentification, un stockage de fichiers, des websockets realtime et le tableau de bord Studio. Vous clonez un dépôt, modifiez un seul fichier .env, puis démarrez environ quatorze conteneurs qui fonctionnent ensemble comme un projet Supabase que vous contrôlez.
L’installation est rapide. Les problèmes viennent du fichier .env. Celui-ci 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 mémoire réellement nécessaire à la stack et la procédure de mise à 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 programme unique. Le fichier Compose démarre plusieurs services distincts sur un même réseau. Savoir à quoi sert chacun permet de comprendre une liste de noms de conteneurs et de diagnostiquer les problèmes.
dbest PostgreSQL avec les extensions Supabase chargées. Tous les autres services s’y connectent. Si ce conteneur n’est pas sain, tous les autres échouent également.kongest l’API gateway. Il écoute sur le port 8000 et route/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 PostgreSQL et le fournit sous forme d’API REST. Une nouvelle table devient ainsi un nouvel endpoint, sans écrire de code.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 websockets.studioetmetacorrespondent au dashboard et à l’API d’administration qui se trouve derrière.analytics(Logflare) etvectorcollectent les journaux, tandis quesupavisorest le pooler de connexions PostgreSQL.
Cette liste explique les valeurs de ressources indiquées plus bas. Vous n’exécutez pas seulement une base de données. Vous exécutez une base de données et une douzaine de services annexes.
Dimensionnement : prévoyez 8 GB de RAM
Sur une installation neuve, la stack consomme environ 2.5 à 3 GB de mémoire résidente en veille, en juillet 2026, avant l’ajout de vos données et de votre trafic. 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 tue un par manque de mémoire, 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 tout service dont vous dépendez. 4 GB peuvent suffire 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 aussi, car Postgres, le volume de stockage et les données de logs résident tous sous le répertoire du projet. Commencez avec 40 GB et surveillez l’utilisation. Compter les services avant de choisir une offre est une bonne habitude pour tout ce que vous auto-hébergez, car PhotoPrism et Immich ont des besoins minimaux réels en RAM, bien supérieurs à ce que laissent entendre leurs pages de démarrage rapide.
Installation : cloner le dépôt officiel
La méthode prise en charge consiste à copier le répertoire docker du dépôt principal vers votre propre répertoire de projet. Cette séparation est importante, car elle empêche une future git pull 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 signifie que le tag d’image épinglé a été supprimé du dépôt amont. Pour la corriger, récupérez une copie plus récente du dépôt au lieu de modifier les tags manuellement.
Les secrets à 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 lors du premier démarrage. Les modifier ensuite implique donc de réinitialiser la base de données.
Le dépôt fournit un générateur qui produit toutes les valeurs correctement, y compris les 2 clés 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, qui est présent sur toute image Ubuntu standard.
Il ne définit pas 2 valeurs. Vous devez les modifier manuellement dans .env :
POSTGRES_PASSWORD. Utilisez uniquement des lettres et des chiffres. La ponctuation dans cette valeur casse les chaînes de connexion que plusieurs services construisent en assemblant des chaînes. L’échec ressemble alors à une erreur d’authentification plutôt qu’à une erreur d’analyse, ce qui oriente les recherches au mauvais endroit.DASHBOARD_USERNAMEetDASHBOARD_PASSWORD. Il s’agit des identifiants d’authentification basique de Studio. Le mot de passe par défaut fourni est littéralementthis_password_is_insecure_and_should_be_updated.
Vous devez comprendre pourquoi ANON_KEY et SERVICE_ROLE_KEY ne peuvent pas être inventés. Ce sont 2 JWT signés avec JWT_SECRET. La gateway vérifie cette signature à 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 fréquent en auto-hébergement : l’opérateur modifie JWT_SECRET, mais conserve les clés de démonstration. Générez toujours les 3 ensemble.
Traitez SERVICE_ROLE_KEY comme un mot de passe root. Il contourne complètement la sécurité au niveau des lignes. Il doit rester dans le code côté serveur, et nulle part ailleurs.
Définissez SITE_URL et API_EXTERNAL_URL avec 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 à http://localhost:8000, tous vos utilisateurs seront redirigés vers leur propre machine.
Vérifiez ensuite vos valeurs :
sh run.sh secretsDémarrez-le et vérifiez qu’il est opérationnel
sh run.sh start
docker compose psrun.sh start encapsule docker compose up -d --wait et ne rend 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 deux à quatre minutes, car Postgres exécute ses scripts d’initialisation avant que tout autre composant puisse se connecter.
Si un conteneur redémarre en boucle, consultez ses journaux avec le nom du service :
docker compose logs db
docker compose logs authStudio est alors accessible sur le port 8000 et vous 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 utilise HTTP en clair sur le port 8000. Chaque clé d’API et chaque mot de passe utilisateur transite sur le réseau en clair. Les identifiants de Studio utilisent l’authentification basic, qui repose sur un encodage base64 et non sur du chiffrement.
Placez un reverse proxy devant Kong et terminez-y TLS (transport layer security). Liez ensuite Kong à l’adresse loopback afin qu’aucun autre hôte ne puisse y accéder. Dans docker-compose.yml, le mapping de ports kong devient 127.0.0.1:8000:8000, puis le proxy transmet les requêtes vers ce port. Traefik devant plusieurs applications Compose explique la gestion des certificats. Ce même proxy finit par être placé devant tous les autres services du serveur, de cette stack jusqu’à une application aussi peu sérieuse que une bibliothèque Jellyfin transformée en vidéoclub des années 90. Chacun de ces services doit utiliser un hostname plutôt qu’un nouveau port ouvert. Si un dashboard ne sert qu’à vous, vous pouvez vous passer du proxy et accéder au port loopback via un tunnel SSH. C’est la même approche que celle utilisée par open-kritt auto-hébergé pour maintenir son interface d’analyse entièrement inaccessible depuis Internet.
Fermez également les autres ports dans le firewall. Docker publie les ports en ajoutant ses propres règles iptables, que la configuration ufw naïve 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 cache et les fichiers sur disque ne sont cohérents qu’au niveau d’un checkpoint. La restauration fonctionnera généralement, mais elle peut aussi perdre silencieusement les dernières transactions. C’est le pire scénario possible pour une sauvegarde.
Utilisez plutôt un dump. pg_dumpall s’exécute dans le conteneur et produit un snapshot 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 ces dumps hors du serveur selon une planification. C’est précisément le rôle de sauvegardes chiffrées déportées avec restic. Un dump planifié qui échoue silencieusement ne se distingue pas d’une absence totale de sauvegarde. Configurez donc la tâche cron ou systemd pour envoyer une alerte sur votre téléphone lorsqu’elle se termine avec un code différent de zéro. Sauvegardez également votre .env au même moment. La perte de JWT_SECRET invalide tous les tokens émis et rend illisible chaque secret chiffré stocké.
Les fichiers envoyés se trouvent dans ./volumes/storage. Ce sont des fichiers ordinaires, donc une simple copie suffit.
Mettre à jour sans perdre de données
Supabase épingle les versions des images dans docker-compose.yml : rien ne change tant que vous ne les mettez pas à jour. Ce principe mérite d’être repris dans toute stack assemblée manuellement. C’est pourquoi un relais RustDesk auto-hébergé épingle ses deux images serveur au lieu de suivre un tag qui évolue : une mise à niveau doit être une opération que vous choisissez d’effectuer un matin où vous avez le temps. 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 de passer à une version majeure. Les mises à niveau majeures de Postgres ne sont pas automatiques. Elles nécessitent un dump et une restauration.
Pour prendre en compte les modifications du fichier Compose lui-même, clonez de nouveau le repository upstream et copiez son répertoire docker dans votre projet. Veillez à ne pas écraser .env.
La réinitialisation complète, qui supprime 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 incohérence. Régénérez les trois valeurs ensemble avec sh utils/generate-keys.sh --update-env, puis exécutez sh run.sh recreate pour 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. Sur une machine de 2 GB, l’out of memory killer arrête des conteneurs 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. Pour 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 système d’authentification renvoyaient-ils 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 sur votre véritable URL publique, puis recréez la stack.