SSD Nodes Learn 8GB di RAM — $66/anno
Guide Matt ConnorDi Matt Connor · Aggiornato 2026-08-02

Come installare Supabase su un VPS con Docker

Guida allo stack Docker ufficiale di Supabase: quali segreti sostituire, cosa fanno i 14 servizi, quanta RAM serve, backup e aggiornamenti sicuri.

Cosa stai configurando

L'hosting autonomo di Supabase consiste nell'eseguire sul proprio server lo stack ufficiale Docker Compose: Postgres, un'API REST che vi si collega, un servizio di autenticazione, l'archiviazione dei file, i websocket realtime e il pannello Studio. Si clona un repository, si modifica un file .env e si avviano circa quattordici container che, insieme, funzionano come un progetto Supabase sotto il proprio controllo.

L'installazione è breve. Il problema principale riguarda il file .env. Contiene segreti di esempio pubblicati nel repository e uno stack avviato con questi valori predefiniti è accessibile a chiunque li individui. Questa guida illustra quali segreti sostituire, a cosa serve ogni servizio, quanta memoria richiede realmente lo stack e come aggiornarlo senza eliminare il database.

Se Docker Compose è una novità, leggere prima Nozioni di base su Docker Compose su un VPS. Tutto ciò che segue presuppone che docker compose version visualizzi già una versione.

Cosa contiene realmente lo stack

Supabase non è un solo programma. Il file Compose avvia un insieme di servizi separati sulla stessa rete. Capire il ruolo di ciascuno trasforma un elenco di nomi di container in un sistema che puoi sottoporre a debug.

  • db è PostgreSQL con le estensioni Supabase caricate. Tutti gli altri servizi comunicano con questo servizio. Se questo container non è integro, anche tutti gli altri servizi non funzionano.
  • kong è il gateway API. È in ascolto sulla porta 8000 e instrada /rest/v1/, /auth/v1/ e /storage/v1/ al backend corretto. È l'unico container che dovresti esporre all'esterno.
  • rest è PostgREST. Legge lo schema Postgres e lo espone come API REST, quindi una nuova tabella diventa un nuovo endpoint senza scrivere codice.
  • auth è GoTrue. Emette i JSON Web Token (JWT) che identificano gli utenti.
  • storage e imgproxy gestiscono il caricamento dei file e il ridimensionamento delle immagini.
  • realtime trasmette le modifiche al database tramite WebSocket.
  • studio e meta sono il dashboard e l'API di amministrazione che lo supporta.
  • analytics (Logflare) e vector raccolgono i log, mentre supavisor è il connection pooler di PostgreSQL.

Questo elenco spiega i valori delle risorse riportati di seguito. Non stai eseguendo solo un database. Stai eseguendo un database insieme a una dozzina di servizi di supporto.

Dimensionamento: pianificare 8 GB di RAM

In una nuova installazione, a luglio 2026, lo stack utilizza a riposo circa 2.5-3 GB di memoria residente, prima di considerare i propri dati o il traffico. Il servizio di analisi e il processo Studio Node.js sono i due maggiori consumatori singoli. Un server con 2 GB avvia i container, poi il kernel ne termina uno tramite il meccanismo di terminazione per esaurimento della memoria, in genere analytics o db. Il sintomo è un container che continua a riavviarsi con codice di uscita 137.

Assegnare 8 GB di RAM e 4 vCPU a qualsiasi ambiente da cui dipendono servizi importanti. 4 GB sono sufficienti per un'istanza di sviluppo utilizzata da una sola persona, se si accetta che una query pesante e una sessione Studio simultanea siano lente. Anche lo spazio su disco è importante, perché Postgres, il volume di archiviazione e i dati dei log si trovano tutti nella directory del progetto. Iniziare con 40 GB e monitorare l'utilizzo.

Installare: clonare il repository ufficiale

La procedura supportata copia la directory docker dal repository principale in una directory di progetto dedicata. Questa separazione è importante perché impedisce a un successivo git pull di sovrascrivere .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 scarica diversi gigabyte di immagini. Al termine, ogni servizio dovrebbe essere contrassegnato come Pulled. Un errore manifest unknown in questa fase indica che il tag dell'immagine specificato è stato rimosso dal repository upstream. Per risolvere il problema, scaricare una copia più recente del repository invece di modificare manualmente i tag.

I segreti da modificare prima del primo avvio

Esegui questa operazione prima di avviare lo stack, non dopo. Al primo avvio, alcuni di questi valori vengono scritti nei dati. Modificarli in seguito richiede quindi il ripristino del database.

Il repository include un generatore che produce correttamente tutti i valori, comprese le due API key che devono essere firmate con il nuovo segreto JWT.

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

Lo script scrive nuovi valori per JWT_SECRET, ANON_KEY, SERVICE_ROLE_KEY, SECRET_KEY_BASE, REALTIME_DB_ENC_KEY, VAULT_ENC_KEY, PG_META_CRYPTO_KEY e i token Logflare in .env. Richiede openssl, presente in qualsiasi immagine Ubuntu standard.

Due valori non vengono impostati dallo script e devono essere modificati manualmente in .env:

  • POSTGRES_PASSWORD. Usa solo lettere e cifre. La punteggiatura in questo valore interrompe le stringhe di connessione che diversi servizi costruiscono concatenando stringhe. L'errore appare come un errore di autenticazione anziché di analisi, portando a cercare la causa nel posto sbagliato.
  • DASHBOARD_USERNAME e DASHBOARD_PASSWORD. Sono le credenziali di autenticazione di base per Studio. La password predefinita fornita è letteralmente this_password_is_insecure_and_should_be_updated.

È importante capire perché ANON_KEY e SERVICE_ROLE_KEY non possono essere inventati. Entrambi sono JWT firmati con JWT_SECRET. Il gateway verifica questa firma a ogni richiesta. Una chiave che non corrisponde al segreto viene quindi rifiutata con {"message":"Invalid authentication credentials"}. Questo è il problema più comune nelle installazioni self-hosted: l'operatore modifica JWT_SECRET, ma mantiene le chiavi dimostrative. Genera sempre tutti e tre i valori insieme.

Tratta SERVICE_ROLE_KEY come una password dell'account root. Ignora completamente la sicurezza a livello di riga. Deve essere usato nel codice lato server e in nessun altro contesto.

Imposta SITE_URL e API_EXTERNAL_URL sull'indirizzo che gli utenti raggiungeranno effettivamente, ad esempio https://supabase.example.com. Auth costruisce i link di conferma dell'e-mail e di callback OAuth a partire da questi valori. Se li lasci su http://localhost:8000, ogni utente verrà reindirizzato al proprio computer.

Controlla quindi i valori configurati:

sh run.sh secrets

Avvialo e verifica che sia operativo

sh run.sh start
docker compose ps

run.sh start esegue il wrapping di docker compose up -d --wait, quindi non restituisce il controllo finché i controlli di salute non vengono superati. Ogni servizio dovrebbe mostrare running (healthy) o running. Il primo avvio richiede da due a quattro minuti, perché Postgres esegue gli script di inizializzazione prima che qualsiasi altro componente possa connettersi.

Se un container viene riavviato, leggi i relativi log usando il nome del servizio:

docker compose logs db
docker compose logs auth

Studio è quindi disponibile sulla porta 8000 e richiederà il nome utente e la password della dashboard configurati.

Non esporre la porta 8000 a Internet pubblico

Kong sulla porta 8000 usa HTTP non cifrato. Ogni chiave API e ogni password utente attraversano la rete in testo in chiaro. Le credenziali di Studio usano inoltre l'autenticazione di base, che codifica i dati in base64 invece di cifrarli.

Colloca un reverse proxy davanti a Kong e termina lì TLS (Transport Layer Security). Associa quindi Kong all'indirizzo di loopback, in modo che nessun altro possa raggiungerlo. In docker-compose.yml, la mappatura della porta kong diventa 127.0.0.1:8000:8000 e il proxy inoltra le richieste a quella porta. Traefik davanti a diverse applicazioni Compose tratta la configurazione dei certificati.

Blocca anche le altre porte nel firewall. Docker pubblica le porte scrivendo proprie regole iptables, che una configurazione ingenua di ufw non rileva. Questo problema è spiegato in perché i container Docker ignorano le regole ufw.

Esegui il backup del database, non della directory

I dati di Postgres si trovano in un bind mount in ./volumes/db/data. Copiare quella directory mentre il container è in esecuzione produce una copia incoerente, perché Postgres memorizza temporaneamente le scritture nei buffer e i file su disco sono coerenti solo durante un checkpoint. Il ripristino di questa copia in genere funziona, ma talvolta causa la perdita silenziosa delle transazioni più recenti. Questo è il peggior tipo di errore possibile per un backup.

Esegui invece un dump. pg_dumpall viene eseguito nel container e produce uno snapshot coerente:

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

Verifica che il file non sia vuoto prima di considerarlo affidabile. Poi trasferisci regolarmente i dump fuori dal server: è questo lo scopo di backup cifrati fuori sede con restic. Esegui contemporaneamente il backup di .env. Se perdi JWT_SECRET, ogni token emesso diventa non valido e ogni segreto cifrato archiviato non è più leggibile.

I file caricati si trovano in ./volumes/storage. Sono file ordinari, quindi è sufficiente una copia semplice.

Aggiornamento senza perdere dati

Supabase fissa le versioni delle immagini in docker-compose.yml, quindi nulla cambia finché non lo aggiorni. Crea prima un dump, ogni volta.

docker compose pull
sh run.sh recreate

recreate arresta lo stack e lo riavvia usando le nuove immagini. I dati restano disponibili perché si trovano nei bind mount sull'host, non all'interno dei container. Leggi CHANGELOG.md nel repository prima di eseguire un aggiornamento alla versione principale successiva, perché gli aggiornamenti delle versioni principali di Postgres non sono automatici e richiedono un dump e un ripristino.

Per applicare le modifiche al file Compose, clona nuovamente il repository upstream e copia la relativa directory docker nel progetto, facendo attenzione a non sovrascrivere .env.

Il ripristino completo, che elimina tutto incluso il database, usa uno script separato e richiede una conferma:

sh reset.sh

FAQ

Perché le mie chiamate API restituiscono "Invalid authentication credentials"?

ANON_KEY o SERVICE_ROLE_KEY non è stato firmato con JWT_SECRET, che è attualmente presente in .env. Il gateway verifica la firma di ogni richiesta e rifiuta le discrepanze. Rigenerate tutti e tre gli elementi insieme con sh utils/generate-keys.sh --update-env, quindi eseguite sh run.sh recreate affinché i servizi leggano i nuovi valori.

Posso eseguire Supabase self-hosted su un VPS da 2 GB?

Non in modo affidabile. A luglio 2026 lo stack utilizza quasi 3 GB in condizioni di inattività perché esegue circa quattordici servizi. Di conseguenza, su una macchina da 2 GB l'out of memory killer arresta i container e in docker compose ps viene visualizzato il codice di uscita 137. Per la produzione usate 8 GB e considerate 4 GB il minimo per lo sviluppo individuale.

Supabase self-hosted include le edge functions?

Sì. Il file Compose include il runtime per le funzioni basato su Deno e serve tutto ciò che inserite in ./volumes/functions. Non include la rete globale di distribuzione della piattaforma in hosting. Le vostre funzioni vengono quindi eseguite sul vostro unico server, in un'unica posizione.

Come posso connettermi direttamente al database Postgres?

Usate docker exec -it supabase-db psql -U postgres per aprire una shell interattiva direttamente sul server. Per un client esterno, connettetevi a Supavisor sulla porta 5432 usando l'utente postgres.<POOLER_TENANT_ID> e il vostro POSTGRES_PASSWORD. Non esponete questa porta a internet. Raggiungetela tramite una VPN o un tunnel SSH.

Perché i messaggi email di conferma dell'autenticazione contenevano collegamenti a localhost?

SITE_URL e API_EXTERNAL_URL in .env erano ancora impostati sui valori predefiniti. Il servizio di autenticazione crea ogni collegamento di conferma e reimpostazione della password a partire da questi due valori, quindi invia l'indirizzo configurato. Impostate entrambi sull'URL pubblico reale e ricreate lo stack.