SSD Nodes Learn Hosting plans →
Guides Matt ConnorPar Matt Connor

Installer Supabase avec Docker sur votre VPS

Déployez la stack Docker officielle de Supabase sur votre serveur : secrets à remplacer, rôle des 11 services, RAM requise, sauvegardes et mises à jour.

Ce que vous allez installer

Auto-héberger Supabase consiste à exécuter la stack Docker Compose officielle 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 onze conteneurs qui fonctionnent ensemble comme un projet Supabase que vous contrôlez.

L’installation est rapide. Les problèmes viennent généralement 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 méthode de mise à jour sans supprimer la base de données.

Si Compose est nouveau pour vous, lisez 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 plusieurs services distincts sur un même réseau. Savoir quel rôle joue chacun permet de transformer une liste de noms de conteneurs en un ensemble que vous pouvez déboguer.

  • db est PostgreSQL avec les extensions Supabase chargées. Tous les autres services communiquent avec lui. Si ce conteneur n’est pas sain, tout le reste échoue également.
  • api-gw est la passerelle API. Depuis la release d’août 2026, elle utilise Envoy. Avant cela, il s’agissait d’un service appelé kong, et Kong reste disponible comme override facultatif. Elle é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.
  • rest est PostgREST. Il lit le schéma Postgres et le publie sous forme d’API REST. Une nouvelle table devient donc un nouvel endpoint, sans code supplémentaire.
  • auth est GoTrue. Il émet les JSON Web Tokens (JWT) qui identifient vos utilisateurs.
  • storage et imgproxy gèrent les téléversements de fichiers et le redimensionnement des images.
  • realtime diffuse les modifications de la base de données via WebSockets.
  • studio et meta correspondent au dashboard et à l’API d’administration qui se trouve derrière.
  • functions est le runtime edge basé sur Deno, et supavisor est le pooler de connexions Postgres.

Les logs et les analytics (Logflare et vector) ont été retirés du fichier Compose par défaut en juin 2026. Ils se trouvent maintenant dans un fichier d’override facultatif que vous activez avec sh run.sh config add logs, selon le même principe de superposition des fichiers Compose que celui décrit dans exécuter une stack à partir de plusieurs fichiers Compose.

Cette liste explique les valeurs de ressources indiquées ci-dessous. Vous n’exécutez pas seulement une base de données. Vous exécutez une base de données et dix services de support.

Dimensionnement : prévoyez 8 GB de RAM

Sur une installation neuve, la stack consommait environ 2.5 à 3 GB de mémoire résidente en juillet 2026, avant la prise en compte de vos données et de votre trafic. Dans cette mesure, le service Analytics et le processus Node.js de Studio étaient les deux plus gros consommateurs individuels. Analytics ne fait plus partie de la stack par défaut. Il ne consomme donc de la mémoire que si vous activez la surcharge de configuration des logs. Un serveur de 2 GB démarre les conteneurs, puis le kernel en arrête un avec l’out-of-memory killer. Le symptôme est un conteneur qui redémarre en boucle avec le code de sortie 137. La documentation Supabase sur le self-hosting, vérifiée en octobre 2026, indique 4 GB de RAM, 2 cœurs CPU et 40 GB de SSD comme configuration minimale, ainsi que 8 GB, 4 cœurs et 80 GB comme configuration recommandée.

Prévoyez 8 GB de RAM et 4 vCPU pour tout service dont vous dépendez. 4 GB suffisent pour une instance de développement individuelle si vous acceptez qu’une requête lourde et une session Studio simultanée soient lentes. Le disque compte également, car Postgres, le volume de stockage et, si vous activez les logs, les données de logs se trouvent tous sous le répertoire du projet. Commencez avec 40 GB et surveillez l’utilisation. Vérifier la consommation des services avant de choisir une offre est une bonne habitude pour tout ce que vous hébergez vous-même, car PhotoPrism et Immich ont eux aussi des besoins minimaux réels en RAM : la page de démarrage rapide d’Immich, vérifiée en octobre 2026, demande au moins 6 GB de RAM et 2 cœurs CPU. Si cette configuration dépasse encore les besoins de votre projet, comparez-la avec ce que comprend réellement l’offre cloud gratuite de Supabase, car une petite application qui reste sous 500 MB et ne reste jamais inactive pendant une semaine peut y fonctionner gratuitement.

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 pull

docker 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

Effectuez cette opération 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 deux clés d’API qui doivent être signées avec votre nouveau secret JWT.

sh utils/generate-keys.sh --update-env

Ce 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, les tokens Logflare, les clés de protocole S3 et MINIO_ROOT_PASSWORD dans .env. Depuis octobre 2026, il écrit également des valeurs aléatoires pour POSTGRES_PASSWORD et DASHBOARD_PASSWORD. Il nécessite openssl, présent sur toute image Ubuntu standard. Comme il réécrit désormais aussi le mot de passe de la base de données, exécutez-le avec --update-env uniquement avant le premier démarrage, jamais sur une stack qui contient déjà des données.

Deux valeurs doivent encore être vérifiées manuellement dans .env :

  • POSTGRES_PASSWORD. Le script le remplit avec une valeur hexadécimale aléatoire, ce qui est sûr. Si vous le remplacez par votre propre valeur, 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 et non à une erreur d’analyse, ce qui oriente les recherches au mauvais endroit.
  • DASHBOARD_USERNAME et DASHBOARD_PASSWORD. Il s’agit des identifiants d’authentification basique de Studio. Le script définit un mot de passe aléatoire, mais conserve le nom d’utilisateur par défaut supabase. Le mot de passe par défaut fourni est littéralement this_password_is_insecure_and_should_be_updated. Si vous avez ignoré le script, modifiez-le maintenant.

Comprenez pourquoi ANON_KEY et SERVICE_ROLE_KEY ne peuvent pas être inventés. Ce sont deux JWT signés avec JWT_SECRET. La gateway n’accepte que les clés exactes présentes dans .env, et les services situés derrière elle vérifient la signature avec JWT_SECRET. Une clé qui ne correspond pas est donc rejetée avec HTTP 401. La gateway Envoy par défaut renvoie 401 Unauthorized. Le remplacement Kong actuel fait de même ; il exécute Kong 3.9 et renvoie {"message":"Unauthorized"}. Les installations antérieures à mars 2026 exécutaient Kong 2.8, qui renvoie {"message":"Invalid authentication credentials"}. C’est l’échec le plus fréquent en auto-hébergement : l’opérateur a modifié JWT_SECRET, mais a conservé les clés de démonstration. Générez toujours les trois valeurs ensemble.

Traitez SERVICE_ROLE_KEY comme un mot de passe root. Il contourne complètement la sécurité au niveau des lignes. Il doit être utilisé dans le code côté serveur, et nulle part ailleurs.

Définissez SITE_URL sur l’adresse de votre application, et API_EXTERNAL_URL sur l’adresse publique de l’API avec /auth/v1 à la fin, par exemple https://supabase.example.com/auth/v1. Définissez SUPABASE_PUBLIC_URL sur la même adresse publique, sans le chemin. Auth construit les liens de confirmation des e-mails et les liens de callback OAuth à partir de ces valeurs. Si vous les laissez sur leurs valeurs par défaut localhost, tous vos utilisateurs seront redirigés vers leur propre machine.

Vérifiez ensuite les valeurs obtenues :

sh run.sh secrets

Démarrez-le et vérifiez qu’il est opérationnel

sh run.sh start
docker compose ps

run.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 auth

Studio 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

La gateway sur le port 8000 utilise HTTP en clair. Toutes les clés d’API et tous les mots de passe utilisateur transitent sur le réseau en clair. Les identifiants du Studio utilisent une authentification basique, qui repose sur un encodage base64 et non sur un chiffrement.

Placez un reverse proxy devant la gateway et terminez-y TLS (transport layer security). Liez ensuite la gateway à l’adresse loopback afin qu’aucun autre hôte ne puisse y accéder. Dans docker-compose.yml, la ligne port sous le service api-gw devient 127.0.0.1:${API_GW_HTTP_PORT:-${KONG_HTTP_PORT:-8000}}:8000/tcp, puis le proxy redirige les requêtes vers ce port. Sur une installation antérieure au passage à Envoy en août 2026, la même ligne port se trouve sous un service appelé kong. Traefik devant plusieurs applications Compose explique la gestion des certificats. Ce même proxy se retrouve ensuite devant tous les autres services de la machine, de cette stack à quelque chose d’aussi peu sérieux qu’une bibliothèque Jellyfin recréée comme un vidéoclub des années 90. Chacun de ces services doit utiliser un nom d’hôte plutôt qu’un nouveau port ouvert. Si un dashboard ne vous est destiné qu’à vous, ignorez le proxy et accédez 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 de scan entièrement hors de portée d’Internet.

Fermez également les autres ports dans le firewall, car Docker publie les ports en écrivant ses propres règles iptables, que la configuration naïve d’ufw ne voit jamais. 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).sql

Vé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 fixe les versions des images dans docker-compose.yml : rien ne change tant que vous ne les modifiez pas. Il est recommandé d’utiliser cette méthode de versionnement dans toute stack assemblée manuellement. C’est pourquoi un relais RustDesk auto-hébergé fixe ses deux images serveur au lieu de suivre un tag qui évolue : une mise à niveau doit être effectuée au moment que vous avez choisi et où vous disposez du temps nécessaire. Effectuez toujours un dump au préalable.

docker compose pull
sh run.sh recreate

recreate arrête la stack, puis la redémarre avec les nouvelles images. Vos données sont conservées, car elles se trouvent dans les bind mounts sur l’hôte, et non dans les conteneurs. Consultez CHANGELOG.md dans le dépôt avant de passer à une version majeure, car une mise à niveau majeure de Postgres est une étape distincte que recreate n’effectue pas. Postgres 17 est la version par défaut depuis juin 2026. Une installation existante sous Postgres 15 passe à cette version avec sudo bash utils/upgrade-pg17.sh, qui utilise pg_upgrade pour migrer les données sur place et demande une confirmation à chaque étape majeure. Tous les conteneurs doivent être en cours d’exécution. Il faut également disposer d’un espace disque libre correspondant à au moins deux fois la taille de votre base de données, plus 5 GB. Supabase recommande toujours d’effectuer votre propre sauvegarde indépendante avant de commencer.

Pour appliquer les modifications apportées au fichier Compose lui-même, exécutez sh update.sh depuis le répertoire du projet, ou sh update.sh --dry-run pour afficher d’abord les changements prévus. Cette commande fusionne les fichiers amont avec vos propres modifications. Elle n’écrase jamais les valeurs existantes dans .env ; elle ajoute uniquement les nouvelles clés. Elle archive votre configuration dans backups/ avant de l’écrire, mais n’archive pas la base de données. Une installation dépourvue de fichier .supabase-version nécessite --from ainsi que la release à partir de laquelle elle a été installée. Ce point est particulièrement important pour la release d’août 2026 : elle a remplacé le service kong par api-gw et nécessite une mise à jour de docker-compose.yml. La méthode manuelle reste également possible : clonez à nouveau le dépôt amont, puis copiez son répertoire docker dans votre projet, en veillant à ne pas écraser .env.

La réinitialisation complète, qui détruit tout, y compris la base de données, et rétablit .env à ses valeurs par défaut (l’ancienne configuration est conservée sous .env.old), utilise un script distinct et demande une confirmation :

sh reset.sh

FAQ

Pourquoi mes appels API renvoient-ils « Invalid authentication credentials » ?

Ce message exact provient de Kong 2.8, la gateway utilisée dans les stacks installées avant mars 2026. La gateway Envoy par défaut et la surcharge Kong actuelle, qui utilise Kong 3.9, signalent le même problème avec un simple 401 Unauthorized. Dans les deux cas, la clé envoyée ne correspond pas à ANON_KEY ou SERVICE_ROLE_KEY dans .env, ou ces clés n’ont pas été signées avec JWT_SECRET actuellement présent dans .env. Sur une stack qui n’a encore jamais contenu de données, régénérez les trois ensemble avec sh utils/generate-keys.sh --update-env. Sur une stack en fonctionnement, exécutez le script sans le flag et répondez non, afin qu’il affiche uniquement les nouvelles valeurs. Copiez manuellement JWT_SECRET, ANON_KEY et SERVICE_ROLE_KEY dans .env, et ne modifiez pas POSTGRES_PASSWORD. Exécutez ensuite 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 documentation officielle d’auto-hébergement de Supabase indique 4 GB de RAM comme minimum depuis octobre 2026. En juillet 2026, la stack utilisait près de 3 GB au repos lors d’une mesure qui incluait les services de logging, désormais activés sur demande. 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 functions basé sur Deno et exécute 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 functions 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. Utilisez un VPN ou un tunnel SSH.

Pourquoi les e-mails de confirmation de mon système d’authentification renvoient-ils vers localhost ?

SITE_URL et API_EXTERNAL_URL dans .env ont 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.