SSD Nodes Learn 8GB RAM — $66/jaar
Gidsen Matt ConnorDoor Matt Connor · Bijgewerkt 2026-08-02

Supabase zelf hosten op een VPS met Docker

Voer de officiële Supabase Docker-stack uit op uw eigen server. Vervang standaardgeheimen, begrijp de 14 services, controleer RAM en regel back-ups en updates.

Wat u bouwt

Supabase zelf hosten betekent dat u de officiële Docker Compose-stack op uw eigen server uitvoert: Postgres, een REST API ervoor, een authenticatieservice, bestandsopslag, realtime-websockets en het Studio-dashboard. U kloont één repository, bewerkt één .env-bestand en start ongeveer veertien containers die samen functioneren als een Supabase-project dat u zelf beheert.

De installatie is kort. Problemen ontstaan meestal door het .env-bestand. Dit bestand bevat standaardgeheimen die in de repository zijn gepubliceerd. Een stack die met deze standaardwaarden wordt gestart, is toegankelijk voor iedereen die deze gegevens vindt. In deze handleiding leest u welke geheimen u moet vervangen, waarvoor elke service dient, hoeveel geheugen de stack werkelijk nodig heeft en hoe u de stack bijwerkt zonder uw database te verwijderen.

Als Compose nieuw voor u is, lees dan eerst De basis van Docker Compose op een VPS. In het onderstaande wordt ervan uitgegaan dat docker compose version al een versienummer weergeeft.

Wat de stack daadwerkelijk bevat

Supabase is niet één programma. Het Compose-bestand start een aantal afzonderlijke services op één netwerk. Als u weet welke service waarvoor dient, kunt u een lange lijst met containernamen doelgericht debuggen.

  • db is PostgreSQL met de Supabase-extensies geladen. Elke andere service maakt hiermee verbinding. Als deze container niet gezond is, falen alle andere services ook.
  • kong is de API-gateway. Deze luistert op poort 8000 en routeert /rest/v1/, /auth/v1/ en /storage/v1/ naar de juiste backend. Dit is de enige container die u ooit extern toegankelijk moet maken.
  • rest is PostgREST. Deze leest uw Postgres-schema en biedt dit als een REST API aan. Daardoor wordt een nieuwe tabel automatisch een nieuw endpoint, zonder code.
  • auth is GoTrue. Deze geeft de JSON-webtokens (JWT's) uit waarmee uw gebruikers worden geïdentificeerd.
  • storage en imgproxy verwerken bestandsuploads en passen het formaat van afbeeldingen aan.
  • realtime streamt databasewijzigingen via websockets.
  • studio en meta zijn het dashboard en de admin-API die daarachter draait.
  • analytics (Logflare) en vector verzamelen logs, en supavisor is de PostgreSQL-verbindingspooler.

Daarom zijn de resourcewaarden hieronder zoals ze zijn. U draait niet alleen een database. U draait een database plus een tiental ondersteunende services.

Formaat: plan voor 8 GB RAM

De stack gebruikt bij inactiviteit ongeveer 2.5 tot 3 GB resident geheugen op een nieuwe installatie, vanaf juli 2026, nog zonder uw eigen data of netwerkverkeer. De analyseservice en het Studio Node.js-proces zijn de twee grootste afzonderlijke verbruikers. Op een server met 2 GB worden de containers gestart, waarna de kernel er meestal één beëindigt via de out-of-memory-killer, doorgaans analytics of db. Het symptoom is een container die blijft herstarten met exit code 137.

Gebruik 8 GB RAM en 4 vCPU voor alles waarvan u afhankelijk bent. 4 GB volstaat voor een ontwikkelinstantie voor één gebruiker, als u accepteert dat een zware query en een Studio-sessie tegelijkertijd traag zijn. Schijfruimte is ook belangrijk, omdat Postgres, het opslagvolume en de loggegevens allemaal onder de projectdirectory staan. Begin met 40 GB en monitor het gebruik.

Installeren: de officiële repository klonen

De ondersteunde werkwijze kopieert de map docker uit de hoofdrepository naar een projectmap die u zelf kiest. Deze scheiding is belangrijk, omdat een latere git pull uw .env daardoor niet kan overschrijven.

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 downloadt meerdere gigabytes aan images. De opdracht moet eindigen met alle services gemarkeerd als Pulled. Een manifest unknown-fout betekent hier dat de vastgelegde imagetag upstream is verwijderd. Haal in dat geval een nieuwere kopie van de repository op in plaats van tags handmatig te wijzigen.

De geheimen die u vóór de eerste start moet wijzigen

Doe dit voordat u de stack start, niet daarna. Verschillende van deze waarden worden bij de eerste start in gegevens opgeslagen. Als u ze later wijzigt, moet u de database opnieuw instellen.

De repository bevat een generator die elke waarde correct aanmaakt, inclusief de twee API keys die met uw nieuwe JWT secret moeten worden ondertekend.

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

Dat script schrijft nieuwe waarden voor JWT_SECRET, ANON_KEY, SERVICE_ROLE_KEY, SECRET_KEY_BASE, REALTIME_DB_ENC_KEY, VAULT_ENC_KEY, PG_META_CRYPTO_KEY en de Logflare tokens naar .env. Hiervoor is openssl nodig. Dit is aanwezig in elke normale Ubuntu image.

Twee waarden worden niet ingesteld. U moet deze handmatig wijzigen in .env:

  • POSTGRES_PASSWORD. Gebruik alleen letters en cijfers. Interpunctie verbreekt hier de connection strings die verschillende services samenstellen door strings aan elkaar te koppelen. De fout lijkt daardoor op een authenticatiefout en niet op een parsefout. Hierdoor zoeken gebruikers vaak op de verkeerde plaats naar de oorzaak.
  • DASHBOARD_USERNAME en DASHBOARD_PASSWORD. Dit zijn de inloggegevens voor basisverificatie van Studio. Het standaardwachtwoord dat wordt meegeleverd is letterlijk this_password_is_insecure_and_should_be_updated.

Zorg dat u begrijpt waarom ANON_KEY en SERVICE_ROLE_KEY niet zelf kunnen worden bedacht. Beide zijn JWTs die met JWT_SECRET zijn ondertekend. De gateway controleert die handtekening bij elk verzoek. Een key die niet overeenkomt met uw secret wordt daarom geweigerd met {"message":"Invalid authentication credentials"}. Dit is de meest voorkomende fout bij self-hosting: de beheerder wijzigt JWT_SECRET, maar behoudt de demo keys. Genereer altijd alle drie samen.

Behandel SERVICE_ROLE_KEY als een root-wachtwoord. Deze waarde omzeilt row level security volledig. Gebruik deze alleen in code aan de serverzijde.

Stel SITE_URL en API_EXTERNAL_URL in op het adres dat uw gebruikers daadwerkelijk zullen bereiken, bijvoorbeeld https://supabase.example.com. Auth maakt de links voor e-mailbevestiging en OAuth-callbacks op basis van deze waarden. Als u ze op http://localhost:8000 laat staan, worden al uw gebruikers naar hun eigen machine gestuurd.

Controleer daarna wat u hebt:

sh run.sh secrets

Start de service en bevestig dat deze gezond is

sh run.sh start
docker compose ps

run.sh start verpakt docker compose up -d --wait, en keert daarom pas terug wanneer de gezondheidscontroles slagen. Elke service moet running (healthy) of running tonen. De eerste start duurt twee tot vier minuten, omdat Postgres de initialisatiescripts uitvoert voordat iets anders verbinding kan maken.

Als een container opnieuw wordt gestart, leest u de logs op servicenaam:

docker compose logs db
docker compose logs auth

Studio is vervolgens beschikbaar op poort 8000 en vraagt om de gebruikersnaam en het wachtwoord voor het dashboard die u hebt ingesteld.

Poort 8000 niet openbaar beschikbaar maken

Kong op poort 8000 gebruikt plain HTTP. Elke API-sleutel en elk gebruikerswachtwoord wordt onversleuteld over het netwerk verzonden. De Studio-inloggegevens gebruiken bovendien basisauthenticatie, waarbij de gegevens met base64 worden gecodeerd in plaats van versleuteld.

Plaats er een reverse proxy voor, beëindig daar TLS (transport layer security) en bind Kong aan het loopbackadres, zodat niets anders er toegang toe heeft. In docker-compose.yml wordt de poorttoewijzing kong gewijzigd in 127.0.0.1:8000:8000. De proxy stuurt vervolgens door naar die poort. Traefik voor meerdere Compose-apps behandelt het certificaatgedeelte.

Blokkeer de overige poorten ook met de firewall. Docker publiceert poorten namelijk door eigen iptables-regels te schrijven, die een eenvoudige ufw-configuratie nooit ziet. Die valkuil wordt uitgelegd in waarom Docker-containers uw ufw-regels negeren.

Maak een back-up van de database, niet van de directory

De Postgres-gegevens staan in een bind mount op ./volumes/db/data. Als u die directory kopieert terwijl de container actief is, krijgt u een inconsistente kopie. Postgres buffert schrijfbewerkingen en de bestanden op schijf zijn alleen consistent tijdens een checkpoint. Herstellen werkt meestal, maar soms gaan de laatste transacties stilzwijgend verloren. Dat is het slechtst mogelijke scenario voor een back-up.

Maak in plaats daarvan een dump. pg_dumpall wordt in de container uitgevoerd en maakt een consistente momentopname:

docker exec -t supabase-db pg_dumpall -U postgres > supabase-$(date +%F).sql

Controleer of het bestand niet leeg is voordat u het vertrouwt. Kopieer deze dumps vervolgens volgens een schema naar een andere server. Daarvoor zijn versleutelde offsite-back-ups met restic bedoeld. Maak tegelijkertijd een back-up van uw .env. Als JWT_SECRET verloren gaat, wordt elk uitgegeven token ongeldig en kan geen enkel opgeslagen versleuteld geheim meer worden gelezen.

Geüploade bestanden staan in ./volumes/storage. Dit zijn gewone bestanden, dus daarvoor volstaat een gewone kopie.

Bijwerken zonder gegevens te verliezen

Supabase legt afbeeldingsversies vast in docker-compose.yml, dus er verandert niets totdat u dit uitvoert. Maak elke keer eerst een dump.

docker compose pull
sh run.sh recreate

recreate stopt de stack en start deze opnieuw met de nieuwe images. Uw gegevens blijven behouden omdat ze in de bind mounts op de host staan, niet in de containers. Lees CHANGELOG.md in de repository voordat u naar een nieuwe major versie gaat, omdat major upgrades van Postgres niet automatisch worden uitgevoerd en een dump en restore vereisen.

Als u wijzigingen in het Compose-bestand wilt overnemen, cloneert u de upstream repository opnieuw en kopieert u de map docker naar uw project. Zorg ervoor dat u .env niet overschrijft.

De volledige reset, waarbij alles inclusief de database wordt verwijderd, is een afzonderlijk script en vraagt om bevestiging:

sh reset.sh

FAQ

Waarom retourneren mijn API-aanroepen "Invalid authentication credentials"?

Uw ANON_KEY of SERVICE_ROLE_KEY is niet ondertekend met de JWT_SECRET die momenteel in .env staat. De gateway controleert de handtekening bij elk verzoek en weigert een niet-overeenkomende handtekening. Genereer alle drie opnieuw met sh utils/generate-keys.sh --update-env en voer daarna sh run.sh recreate uit, zodat de services de nieuwe waarden inlezen.

Kan ik self-hosted Supabase uitvoeren op een VPS met 2 GB?

Niet betrouwbaar. De stack gebruikt sinds July 2026 in rust bijna 3 GB, omdat deze ongeveer fourteen services uitvoert. Daardoor beëindigt de out of memory killer containers op een systeem met 2 GB en ziet u exit code 137 in docker compose ps. Gebruik 8 GB voor productie en beschouw 4 GB als het minimum voor individuele ontwikkeling.

Bevat self-hosted Supabase edge functions?

Ja. Het Compose-bestand bevat de Deno based functions runtime en verwerkt alles wat u onder ./volumes/functions plaatst. De wereldwijde deployment network van het gehoste platform is niet inbegrepen. Uw functions worden daarom op uw ene server en op één locatie uitgevoerd.

Hoe maak ik rechtstreeks verbinding met de Postgres-database?

Gebruik docker exec -it supabase-db psql -U postgres voor een interactieve shell op de server zelf. Gebruik voor een externe client Supavisor op port 5432 met de gebruiker postgres.<POOLER_TENANT_ID> en uw POSTGRES_PASSWORD. Stel die port niet open voor het internet. Maak verbinding via een VPN of een SSH-tunnel.

Waarom verwezen de bevestigingsmails voor mijn auth naar localhost?

SITE_URL en API_EXTERNAL_URL in .env hadden nog hun standaardwaarden. De auth-service bouwt elke link voor bevestiging en wachtwoordreset op basis van deze twee waarden. Daarom verstuurt de service het adres dat u hebt geconfigureerd. Stel beide waarden in op uw echte openbare URL en maak de stack opnieuw aan.