SSD Nodes Learn 8GB RAM — $66/Jahr
Anleitungen Matt ConnorVon Matt Connor · Aktualisiert 2026-08-01

Supabase selbst hosten: Docker auf einem VPS einrichten

Betreiben Sie den offiziellen Supabase-Docker-Stack auf Ihrem VPS: Ersetzen Sie Demo-Secrets, verstehen Sie 14 Services, planen Sie RAM, Backups und Updates.

Was Sie aufbauen

Supabase selbst zu hosten bedeutet, den offiziellen Docker-Compose-Stack auf Ihrem eigenen Server auszuführen: Postgres, eine REST-API davor, einen Authentifizierungsdienst, Dateispeicher, Realtime-WebSockets und das Studio-Dashboard. Sie klonen ein Repository, bearbeiten eine .env-Datei und starten etwa vierzehn Container, die zusammen wie ein Supabase-Projekt funktionieren, das Sie selbst kontrollieren.

Die Installation ist kurz. Probleme verursacht die .env-Datei. Sie enthält Demo-Secrets, die im Repository veröffentlicht sind. Ein Stack, der mit diesen Standardwerten gestartet wird, ist für jeden offen, der ihn findet. Diese Anleitung behandelt die Secrets, die Sie ersetzen müssen, den Zweck der einzelnen Dienste, den tatsächlichen Speicherbedarf des Stacks und die Aktualisierung, ohne Ihre Datenbank zu löschen.

Wenn Compose für Sie neu ist, lesen Sie zuerst Docker-Compose-Grundlagen auf einem VPS. Im Folgenden wird vorausgesetzt, dass docker compose version bereits eine Version ausgibt.

Was der Stack tatsächlich enthält

Supabase ist kein einzelnes Programm. Die Compose-Datei startet eine Gruppe separater Services in einem Netzwerk. Wenn Sie die einzelnen Services kennen, können Sie eine unübersichtliche Liste von Containern gezielt debuggen.

  • db ist PostgreSQL mit geladenen Supabase-Erweiterungen. Jeder andere Service kommuniziert damit. Wenn dieser Container nicht fehlerfrei arbeitet, schlagen auch alle anderen Services fehl.
  • kong ist das API-Gateway. Es lauscht an Port 8000 und leitet /rest/v1/, /auth/v1/ und /storage/v1/ an das jeweils zuständige Backend weiter. Nur diesen Container sollten Sie nach außen erreichbar machen.
  • rest ist PostgREST. Es liest Ihr Postgres-Schema und stellt es als REST-API bereit. Dadurch wird eine neue Tabelle ohne zusätzlichen Code zu einem neuen Endpunkt.
  • auth ist GoTrue. Es stellt die JSON Web Tokens (JWT) aus, die Ihre Benutzer identifizieren.
  • storage und imgproxy verarbeiten Datei-Uploads und skalieren Bilder.
  • realtime überträgt Datenbankänderungen über WebSockets.
  • studio und meta sind das Dashboard und die dahinterliegende Admin-API.
  • analytics (Logflare) und vector sammeln Logs. supavisor ist der PostgreSQL-Verbindungspooler.

Diese Liste erklärt, warum die folgenden Ressourcenwerte so gewählt sind. Sie betreiben nicht nur eine Datenbank. Sie betreiben eine Datenbank zusammen mit einem Dutzend unterstützender Services.

Größenplanung: Planen Sie 8 GB RAM ein

Der Stack belegt bei einer frischen Installation im Leerlauf ungefähr 2.5 bis 3 GB Arbeitsspeicher, Stand Juli 2026, bevor eigene Daten oder Netzwerkverkehr hinzukommen. Der Analysedienst und der Studio Node.js-Prozess verbrauchen jeweils am meisten Speicher. Ein Server mit 2 GB startet die Container und verliert anschließend einen davon an den Out-of-Memory-Killer des Kernels, normalerweise analytics oder db. Das zeigt sich meist an einem Container, der mit Exit-Code 137 ständig neu gestartet wird.

Geben Sie dem System für alles, worauf Sie angewiesen sind, 8 GB RAM und 4 vCPU. 4 GB reichen für eine allein verwendete Entwicklungsinstanz aus, wenn Sie akzeptieren, dass eine umfangreiche Abfrage und eine Studio-Sitzung gleichzeitig langsam sind. Auch der Datenträger ist wichtig, weil Postgres, das Speichervolume und die Protokolldaten im Projektverzeichnis liegen. Beginnen Sie mit 40 GB und überwachen Sie die Auslastung.

Installation: Das offizielle Repository klonen

Der unterstützte Weg kopiert das Verzeichnis docker aus dem Haupt-Repository in ein eigenes Projektverzeichnis. Diese Trennung ist wichtig, weil ein späteres git pull dadurch Ihr .env nicht überschreiben kann.

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 lädt mehrere Gigabyte an Images herunter. Der Befehl sollte mit jedem Dienst im Status Pulled enden. Ein manifest unknown-Fehler bedeutet hier, dass der festgelegte Image-Tag upstream entfernt wurde. Die Lösung besteht darin, eine neuere Kopie des Repositorys abzurufen, statt die Tags manuell zu bearbeiten.

Die Geheimnisse, die Sie vor dem ersten Start ändern müssen

Führen Sie dies aus, bevor Sie den Stack starten, nicht danach. Mehrere dieser Werte werden beim ersten Start in Daten geschrieben. Wenn Sie sie später ändern, müssen Sie die Datenbank zurücksetzen.

Das Repository enthält einen Generator, der jeden Wert korrekt erzeugt. Dazu gehören auch die beiden API-Schlüssel, die mit Ihrem neuen JWT-Schlüssel signiert werden müssen.

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

Das Skript schreibt neue Werte für JWT_SECRET, ANON_KEY, SERVICE_ROLE_KEY, SECRET_KEY_BASE, REALTIME_DB_ENC_KEY, VAULT_ENC_KEY, PG_META_CRYPTO_KEY und die Logflare-Token in .env. Es benötigt openssl. Dieses ist in jedem normalen Ubuntu-Image vorhanden.

Zwei Werte setzt das Skript nicht. Diese müssen Sie in .env manuell bearbeiten:

  • POSTGRES_PASSWORD. Verwenden Sie ausschließlich Buchstaben und Ziffern. Satzzeichen verursachen hier Fehler in den Verbindungszeichenfolgen, die mehrere Dienste durch das Zusammenfügen von Zeichenfolgen erstellen. Der Fehler sieht wie ein Authentifizierungsfehler und nicht wie ein Parsing-Fehler aus. Dadurch wird oft an der falschen Stelle nach der Ursache gesucht.
  • DASHBOARD_USERNAME und DASHBOARD_PASSWORD. Dies sind die Zugangsdaten für die Standardauthentifizierung von Studio. Das mitgelieferte Standardpasswort lautet wörtlich this_password_is_insecure_and_should_be_updated.

Beachten Sie, warum ANON_KEY und SERVICE_ROLE_KEY nicht frei erfunden werden können. Beide sind JWTs, die mit JWT_SECRET signiert werden. Das Gateway überprüft diese Signatur bei jeder Anfrage. Ein Schlüssel, der nicht zu Ihrem Geheimnis passt, wird daher mit {"message":"Invalid authentication credentials"} abgewiesen. Dies ist der häufigste Fehler beim Self-Hosting: Der Betreiber ändert JWT_SECRET, behält aber die Demo-Schlüssel bei. Erzeugen Sie immer alle drei Werte gemeinsam.

Behandeln Sie SERVICE_ROLE_KEY wie ein root-Passwort. Der Wert umgeht die Row-Level-Security vollständig. Er gehört in serverseitigen Code und an keinen anderen Ort.

Setzen Sie SITE_URL und API_EXTERNAL_URL auf die Adresse, unter der Ihre Benutzer den Dienst tatsächlich erreichen, zum Beispiel https://supabase.example.com. Auth erstellt daraus Links zur E-Mail-Bestätigung und zu OAuth-Callbacks. Wenn Sie die Werte auf http://localhost:8000 belassen, werden alle Benutzer auf ihren jeweils eigenen Computer weitergeleitet.

Überprüfen Sie anschließend Ihre Werte:

sh run.sh secrets

Starten Sie es und bestätigen Sie den fehlerfreien Betrieb

sh run.sh start
docker compose ps

run.sh start umschließt docker compose up -d --wait und kehrt daher erst zurück, wenn die Zustandsprüfungen erfolgreich sind. Jeder Dienst sollte running (healthy) oder running anzeigen. Der erste Start dauert zwei bis vier Minuten, weil Postgres seine Initialisierungsskripte ausführt, bevor eine andere Komponente eine Verbindung herstellen kann.

Wenn ein Container neu gestartet wird, lesen Sie seine Logs anhand des Dienstnamens:

docker compose logs db
docker compose logs auth

Studio ist anschließend über Port 8000 erreichbar und fordert den von Ihnen festgelegten Benutzernamen und das Passwort für das Dashboard an.

Port 8000 nicht im öffentlichen Internet bereitstellen

Kong verwendet auf Port 8000 unverschlüsseltes HTTP. Jeder API-Schlüssel und jedes Benutzerpasswort wird im Klartext über das Netzwerk übertragen. Die Anmeldedaten für Studio verwenden Basic Authentication, also Base64-Kodierung statt Verschlüsselung.

Schalten Sie einen Reverse Proxy davor und beenden Sie dort TLS (Transport Layer Security). Binden Sie Kong an die Loopback-Adresse, damit kein anderer Dienst darauf zugreifen kann. In docker-compose.yml wird die Portzuordnung kong zu 127.0.0.1:8000:8000, und der Proxy leitet Anfragen dorthin weiter. Traefik vor mehreren Compose-Apps behandelt die Zertifikatskonfiguration.

Sperren Sie die übrigen Ports ebenfalls in der Firewall. Docker veröffentlicht Ports, indem es eigene iptables-Regeln schreibt. Eine einfache ufw-Konfiguration berücksichtigt diese Regeln nicht. Diese Falle wird unter warum Docker-Container Ihre ufw-Regeln ignorieren erklärt.

Sichern Sie die Datenbank, nicht das Verzeichnis

Postgres-Daten liegen in einem Bind-Mount unter ./volumes/db/data. Wenn Sie dieses Verzeichnis kopieren, während der Container läuft, erhalten Sie eine inkonsistente Kopie. Postgres puffert Schreibvorgänge. Die Dateien auf dem Datenträger sind erst an einem Checkpoint konsistent. Die Wiederherstellung funktioniert meistens, kann aber stillschweigend die letzten Transaktionen verlieren. Das ist der schlimmste mögliche Fehler bei einer Sicherung.

Erstellen Sie stattdessen einen Dump. pg_dumpall wird im Container ausgeführt und erzeugt einen konsistenten Snapshot:

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

Prüfen Sie, dass die Datei nicht leer ist, bevor Sie ihr vertrauen. Übertragen Sie diese Dumps anschließend regelmäßig vom Server an einen anderen Speicherort. Dafür sind verschlüsselte Offsite-Sicherungen mit restic vorgesehen. Sichern Sie gleichzeitig Ihr .env. Wenn JWT_SECRET verloren geht, werden alle ausgestellten Token ungültig und alle gespeicherten verschlüsselten Geheimnisse unlesbar.

Hochgeladene Dateien liegen in ./volumes/storage. Dabei handelt es sich um gewöhnliche Dateien, daher ist eine einfache Kopie ausreichend.

Aktualisieren, ohne Daten zu verlieren

Supabase legt die Image-Versionen in docker-compose.yml fest. Daher ändert sich nichts, bis Sie ein Update durchführen. Erstellen Sie vorher immer ein Dump.

docker compose pull
sh run.sh recreate

recreate stoppt den Stack und startet ihn mit den neuen Images erneut. Ihre Daten bleiben erhalten, weil sie in den Bind-Mounts auf dem Host liegen und nicht in den Containern. Lesen Sie vor einem Sprung auf eine neue Hauptversion CHANGELOG.md im Repository. Upgrades der PostgreSQL-Hauptversion erfolgen nicht automatisch und erfordern ein Dump und eine Wiederherstellung.

Um Änderungen an der Compose-Datei zu übernehmen, klonen Sie das Upstream-Repository erneut und kopieren dessen Verzeichnis docker über Ihr Projekt. Überschreiben Sie dabei nicht .env.

Für einen vollständigen Reset, der alles einschließlich der Datenbank löscht, gibt es ein separates Script. Es fordert eine Bestätigung an:

sh reset.sh

FAQ

Warum geben meine API-Aufrufe „Ungültige Authentifizierungsdaten“ zurück?

Ihr ANON_KEY oder SERVICE_ROLE_KEY wurde nicht mit dem JWT_SECRET signiert, das derzeit in .env verwendet wird. Das Gateway überprüft die Signatur jeder Anfrage und weist eine Abweichung zurück. Erzeugen Sie alle drei Werte gemeinsam mit sh utils/generate-keys.sh --update-env neu. Führen Sie anschließend sh run.sh recreate aus, damit die Dienste die neuen Werte einlesen.

Kann ich selbst gehostetes Supabase auf einem VPS mit 2 GB ausführen?

Nicht zuverlässig. Der Stack benötigt seit Juli 2026 im Leerlauf fast 3 GB, da er etwa vierzehn Dienste ausführt. Auf einem System mit 2 GB beendet der Out-of-Memory-Killer daher Container, und in docker compose ps wird der Exit-Code 137 angezeigt. Verwenden Sie für den Produktivbetrieb 8 GB. Für die alleinige Entwicklung sind 4 GB die Untergrenze.

Enthält selbst gehostetes Supabase Edge Functions?

Ja. Die Compose-Datei enthält die Deno-basierte Laufzeit für Functions. Sie stellt alles bereit, was Sie unter ./volumes/functions ablegen. Das globale Deployment-Netzwerk der gehosteten Plattform ist nicht enthalten. Ihre Functions laufen daher auf Ihrem einzelnen Server an einem einzigen Standort.

Wie verbinde ich mich direkt mit der Postgres-Datenbank?

Verwenden Sie docker exec -it supabase-db psql -U postgres für eine interaktive Shell direkt auf dem Server. Für einen externen Client stellen Sie über Supavisor auf Port 5432 eine Verbindung mit dem Benutzer postgres.<POOLER_TENANT_ID> und Ihrem POSTGRES_PASSWORD her. Öffnen Sie diesen Port nicht für das Internet. Greifen Sie über ein VPN oder einen SSH-Tunnel darauf zu.

SITE_URL und API_EXTERNAL_URL in .env hatten weiterhin ihre Standardwerte. Der Auth-Dienst erstellt jeden Link zur Bestätigung und zum Zurücksetzen des Passworts aus diesen beiden Werten. Daher verwendet er die Adresse, die dort konfiguriert ist. Setzen Sie beide Werte auf Ihre echte öffentliche URL und erstellen Sie den Stack neu.