SSD Nodes Learn Hosting plans →
Mga Gabay Matt ConnorNi Matt Connor · Na-update 2026-08-27

Paano Mag-self-host ng Supabase sa VPS gamit ang Docker

Patakbuhin ang official Supabase Docker stack sa sarili mong server. Alamin ang secrets na papalitan, gamit ng 14 services, RAM needs, backups, at updates.

Mga binubuo mo

Ang self-hosting ng Supabase ay nangangahulugang pinapatakbo mo sa sarili mong server ang official Docker Compose stack: Postgres, REST API na nakaharap dito, auth service, file storage, realtime websockets, at Studio dashboard. Iki-clone mo ang isang repository, ie-edit ang isang .env file, at magpapatakbo ng humigit-kumulang labing-apat na container na sama-samang kumikilos bilang isang Supabase project na ikaw ang kumokontrol.

Maikli ang installation. Ang karaniwang nagiging problema ay ang .env file. May kasama itong demo secrets na naka-publish sa repository, kaya ang stack na sinimulan gamit ang mga default na iyon ay bukas sa sinumang makadiskubre nito. Saklaw ng gabay na ito ang mga secret na kailangan mong palitan, gamit ng bawat service, aktuwal na memory na kailangan ng stack, at paraan ng pag-update dito nang hindi dine-delete ang database mo.

Kung bago sa iyo ang Compose, basahin muna ang Mga pangunahing kaalaman sa Docker Compose sa isang VPS. Ipinapalagay ng lahat ng sumusunod na nagpi-print na ng version ang docker compose version.

Mga aktuwal na component ng stack

Ang Supabase ay hindi iisang program. Sinisimulan ng Compose file ang isang set ng magkakahiwalay na service sa iisang network. Kapag alam mo kung ano ang tungkulin ng bawat isa, mas madaling i-debug ang maraming pangalan ng container.

  • db ang PostgreSQL na may naka-load na Supabase extensions. Lahat ng iba pang service ay kumokonekta rito. Kapag unhealthy ang container na ito, mabibigo rin ang lahat ng iba pa.
  • kong ang API gateway. Nakikinig ito sa port 8000 at niruruta ang /rest/v1/, /auth/v1/, at /storage/v1/ sa tamang backend. Ito lamang ang container na dapat mong i-expose.
  • rest ang PostgREST. Binabasa nito ang schema ng Postgres at inihahatid ito bilang REST API. Dahil dito, nagiging bagong endpoint ang isang bagong table nang walang kailangang code.
  • auth ang GoTrue. Gumagawa ito ng JSON web tokens (JWT) na kumikilala sa iyong mga user.
  • storage at imgproxy ang namamahala sa file upload at image resizing.
  • realtime ang nag-stream ng mga pagbabago sa database gamit ang websockets.
  • studio at meta ang dashboard at ang admin API na ginagamit nito.
  • analytics (Logflare) at vector ang nangongolekta ng logs, at supavisor ang Postgres connection pooler.

Iyan ang dahilan kung bakit ganoon ang resource numbers sa ibaba. Hindi lang database ang pinapatakbo mo. Database ito kasama ang dose-dosenang support service.

Sizing: magplano para sa 8 GB ng RAM

Umaabot sa humigit-kumulang 2.5 hanggang 3 GB ang resident memory na ginagamit ng stack kapag idle sa bagong install, batay sa kalagayan noong July 2026, bago pa idagdag ang sarili mong data o traffic. Ang analytics service at ang Studio Node.js process ang dalawang pinakamalaking indibidwal na consumer. Sa 2 GB na server, magsisimula ang containers ngunit kalaunan ay papatayin ng kernel out-of-memory killer ang isa sa mga ito, karaniwang analytics o db. Ang sintomas nito ay container na patuloy na nagre-restart at may exit code 137.

Gumamit ng 8 GB ng RAM at 4 vCPU para sa anumang serbisyong aasahan mo. Sapat ang 4 GB para sa solo development instance kung tatanggapin mong magiging mabagal kapag sabay na nagpapatakbo ng heavy query at Studio session. Mahalaga rin ang disk dahil nasa project directory ang Postgres, storage volume, at log data. Magsimula sa 40 GB at i-monitor ang paggamit nito. Ugaliing bilangin muna ang mga service bago pumili ng plan para sa anumang self-hosted na application, dahil ang PhotoPrism at Immich ay may aktuwal na RAM floor na mas mataas kaysa sa ipinahihiwatig ng kanilang quick start pages.

I-install: i-clone ang opisyal na repository

Kinokopya ng suportadong paraan ang directory na docker mula sa pangunahing repository papunta sa sarili mong project directory. Mahalaga ang paghihiwalay na ito dahil hindi mao-overwrite ng susunod na git pull ang iyong .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

Nagda-download ang docker compose pull ng ilang gigabyte ng images. Dapat itong magtapos na ang bawat service ay may markang Pulled. Ang error na manifest unknown dito ay nangangahulugang inalis sa upstream ang naka-pin na image tag. Ang solusyon ay kumuha ng mas bagong kopya ng repository sa halip na manu-manong baguhin ang mga tag.

Mga secret na kailangan mong baguhin bago ang unang pagsisimula

Gawin ito bago mo simulan ang stack, hindi pagkatapos. Isinusulat ang ilan sa mga value na ito sa data sa unang boot, kaya ang pagpapalit sa mga ito sa bandang huli ay nangangahulugang kailangang i-reset ang database.

May generator ang repository na gumagawa ng bawat value nang tama, kasama ang dalawang API key na kailangang i-sign gamit ang bago mong JWT secret.

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

Sumusulat ang script na iyon ng mga bagong value para sa JWT_SECRET, ANON_KEY, SERVICE_ROLE_KEY, SECRET_KEY_BASE, REALTIME_DB_ENC_KEY, VAULT_ENC_KEY, PG_META_CRYPTO_KEY at mga Logflare token sa .env. Kailangan nito ang openssl, na available sa anumang normal na Ubuntu image.

May dalawang value itong hindi sine-set, kaya kailangan mong manu-manong i-edit ang mga ito sa .env:

  • POSTGRES_PASSWORD. Mga letra at digit lamang ang gamitin. Sinisira ng punctuation dito ang connection string na binubuo ng ilang serbisyo sa pamamagitan ng pagsasama-sama ng mga string. Nagmumukhang authentication error ang failure sa halip na parsing error, kaya sa maling lugar naghahanap ng problema ang mga tao.
  • DASHBOARD_USERNAME at DASHBOARD_PASSWORD. Ito ang basic authentication credentials para sa Studio. Ang default password na kasama sa package ay literal na this_password_is_insecure_and_should_be_updated.

Unawain kung bakit hindi maaaring basta imbentuhin ang ANON_KEY at SERVICE_ROLE_KEY. Pareho itong JWT na naka-sign gamit ang JWT_SECRET. Vine-verify ng gateway ang signature na iyon sa bawat request, kaya tatanggihan ang key na hindi tugma sa iyong secret, na may {"message":"Invalid authentication credentials"}. Ito ang pinakakaraniwang failure sa self-hosting: binago ng operator ang JWT_SECRET pero iniwan ang demo keys. Sabay na i-generate ang tatlo, palagi.

Ituring ang SERVICE_ROLE_KEY na parang root password. Lubos nitong nilalampasan ang row level security. Dapat lamang itong ilagay sa server-side code at wala nang iba.

Itakda ang SITE_URL at API_EXTERNAL_URL sa address na aktuwal na maaabot ng iyong mga user, halimbawa https://supabase.example.com. Binubuo ng Auth ang mga link para sa email confirmation at OAuth callback mula sa mga value na iyon. Kaya kapag iniwan ang mga ito sa http://localhost:8000, mapupunta ang bawat user mo sa sarili nilang machine.

Pagkatapos, suriin ang mga value na mayroon ka:

sh run.sh secrets

Simulan ito at tiyaking gumagana nang maayos

sh run.sh start
docker compose ps

Ang run.sh start ay naghihintay sa docker compose up -d --wait, kaya hindi ito magbabalik hangga’t hindi pumapasa ang health checks. Dapat ipakita ng bawat service ang running (healthy) o running. Ang unang boot ay tumatagal ng dalawa hanggang apat na minuto dahil pinapatakbo muna ng Postgres ang mga initialization script nito bago makakonekta ang alinmang component.

Kung patuloy na nagre-restart ang isang container, basahin ang logs nito gamit ang pangalan ng service:

docker compose logs db
docker compose logs auth

Makikita na ang Studio sa port 8000. Hihingin nito ang dashboard username at password na itinakda mo.

Huwag ilagay sa public internet ang port 8000

Plain HTTP ang ginagamit ng Kong sa port 8000. Dumadaan sa network nang clear text ang bawat API key at password ng user. Basic authentication ang credentials ng Studio, at base64 encoding lang ito, hindi encryption.

Maglagay ng reverse proxy sa harap nito at doon i-terminate ang TLS (transport layer security). I-bind ang Kong sa loopback address para walang ibang makakonekta rito. Sa docker-compose.yml, magiging 127.0.0.1:8000:8000 ang port mapping na kong, at ipapasa iyon ng proxy. Tinutukoy sa Traefik sa harap ng ilang Compose app ang certificate setup.

Isara rin ang iba pang port sa firewall. Nagpa-publish ang Docker ng mga port sa pamamagitan ng sarili nitong iptables rules. Hindi ito nakikita ng karaniwang configuration ng ufw. Ipinaliliwanag ang problemang ito sa kung bakit binabalewala ng Docker containers ang iyong ufw rules.

I-backup ang database, hindi ang directory

Nasa bind mount ang Postgres data sa ./volumes/db/data. Kapag kinopya mo ang directory habang tumatakbo ang container, magiging hindi kumpleto ang kopya dahil bina-buffer ng Postgres ang mga write at nagiging consistent lamang ang mga file sa disk kapag may checkpoint. Karaniwang gagana ang pag-restore nito, pero kung minsan ay tahimik na mawawala ang mga pinakahuling transaction. Ito ang pinakamasamang posibleng failure mode para sa isang backup.

Sa halip, mag-dump. Tumatakbo sa loob ng container ang pg_dumpall at gumagawa ito ng consistent na snapshot:

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

Tiyaking hindi empty ang file bago mo ito pagkatiwalaan. Pagkatapos, regular na ipadala ang mga dump na iyon sa labas ng server. Iyan ang gamit ng encrypted offsite backups gamit ang restic. I-back up din kasabay nito ang .env. Kapag nawala ang JWT_SECRET, magiging invalid ang bawat na-issue na token at hindi na mababasa ang bawat naka-store na encrypted secret.

Nasa ./volumes/storage ang mga uploaded file. Ordinary files ang mga ito, kaya sapat na ang plain copy.

Mag-update nang hindi nawawala ang data

Pini-pin ng Supabase ang mga image version sa docker-compose.yml, kaya walang magbabago hangga’t hindi mo ito ina-update. Mainam na gayahin ang pinning sa anumang stack na mano-mano mong binubuo. Kaya pini-pin ng self-hosted na RustDesk relay ang dalawang server image nito sa halip na gumamit ng tag na patuloy na nagbabago. Dapat ikaw ang pumili kung kailan mag-a-upgrade, sa oras na may sapat kang panahon para dito. Laging gumawa muna ng dump.

docker compose pull
sh run.sh recreate

Itinitigil ng recreate ang stack at sinisimulan itong muli gamit ang mga bagong image. Nananatili ang data dahil nasa bind mounts ito sa host, hindi sa loob ng mga container. Basahin ang CHANGELOG.md sa repository bago gumawa ng major version jump, dahil hindi awtomatiko ang major upgrade ng Postgres at kailangan nito ng dump at restore.

Para makuha ang mga pagbabago mismo sa Compose file, i-clone muli ang upstream repository at kopyahin ang directory nitong docker papunta sa iyong project. Mag-ingat na huwag ma-overwrite ang .env.

Ang full reset, na nagbubura ng lahat pati ng database, ay hiwalay na script at humihingi ito ng confirmation:

sh reset.sh

FAQ

Bakit nagbabalik ng "Invalid authentication credentials" ang mga API call ko?

Hindi nilagdaan ang ANON_KEY o SERVICE_ROLE_KEY gamit ang JWT_SECRET na kasalukuyang nasa .env. Bine-verify ng gateway ang signature sa bawat request at tinatanggihan ang hindi tugma. I-regenerate ang tatlo nang sabay gamit ang sh utils/generate-keys.sh --update-env, pagkatapos ay patakbuhin ang sh run.sh recreate upang mabasa ng mga serbisyo ang mga bagong value.

Maaari ko bang patakbuhin ang self-hosted Supabase sa 2 GB VPS?

Hindi ito maaasahan. Umaabot sa halos 3 GB ang idle memory usage ng stack noong July 2026 dahil nagpapatakbo ito ng humigit-kumulang labing-apat na serbisyo. Dahil dito, nawawalan ng containers ang 2 GB na server dahil sa out of memory killer, at makikita mo ang exit code 137 sa docker compose ps. Gumamit ng 8 GB para sa production, at ituring ang 4 GB bilang minimum para sa solo development.

Kasama ba sa self-hosted Supabase ang edge functions?

Oo. Kasama sa Compose file ang Deno-based functions runtime, at sini-serve nito ang anumang ilalagay mo sa ./volumes/functions. Hindi kasama rito ang global deployment network ng hosted platform. Kaya tatakbo ang iyong functions sa iisang server at iisang lokasyon.

Paano ako direktang kokonekta sa Postgres database?

Gamitin ang docker exec -it supabase-db psql -U postgres para sa interactive shell sa mismong server. Para sa external client, kumonekta sa Supavisor sa port 5432 gamit ang user na postgres.<POOLER_TENANT_ID> at ang iyong POSTGRES_PASSWORD. Huwag buksan ang port na iyon sa internet. I-access ito sa pamamagitan ng VPN o SSH tunnel.

Naiwan sa default ang SITE_URL at API_EXTERNAL_URL sa .env. Binubuo ng auth service ang bawat confirmation at password reset link mula sa dalawang value na ito. Kaya ipinapadala nito ang address na itinakda rito. Itakda ang parehong value sa iyong aktuwal na public URL, pagkatapos ay i-recreate ang stack.