SSD Nodes Learn Hosting plans →
Panduan Matt ConnorOleh Matt Connor · Diperbarui 2026-10-20

Cara Self-Host Supabase di VPS dengan Docker

Jalankan stack Docker Supabase resmi di server sendiri. Ganti secret demo di `.env`, pahami 11 service, siapkan RAM, backup database, dan perbarui stack dengan aman.

Yang Anda bangun

Self-hosting Supabase berarti menjalankan stack Docker Compose resmi pada server Anda sendiri: Postgres, REST API di depannya, layanan autentikasi, penyimpanan file, websocket realtime, dan dashboard Studio. Anda mengkloning satu repository, mengedit satu file .env, lalu menjalankan sebelas container yang bersama-sama berfungsi seperti project Supabase yang Anda kendalikan.

Proses instalasinya singkat. Masalah biasanya berasal dari file .env. File tersebut berisi secret demo yang dipublikasikan di repository, sehingga stack yang dijalankan dengan nilai default itu dapat diakses oleh siapa saja yang menemukannya. Panduan ini menjelaskan secret yang harus Anda ganti, fungsi setiap service, kebutuhan memori stack yang sebenarnya, serta cara memperbaruinya tanpa menghapus database.

Jika Compose masih baru bagi Anda, baca Dasar-dasar Docker Compose pada VPS terlebih dahulu. Semua langkah di bawah mengasumsikan docker compose version sudah menampilkan versi.

Isi sebenarnya dari stack

Supabase bukan satu program. File Compose memulai sekumpulan service terpisah dalam satu network. Memahami fungsi masing-masing service mengubah daftar nama container yang panjang menjadi sesuatu yang dapat Anda debug.

  • db adalah PostgreSQL dengan ekstensi Supabase yang telah dimuat. Semua service lain berkomunikasi dengannya. Jika container ini tidak sehat, service lainnya juga gagal.
  • api-gw adalah API gateway. Sejak rilis August 2026, service ini menjalankan Envoy. Sebelumnya, service ini bernama kong, dan Kong masih tersedia sebagai override opsional. Service ini listening pada port 8000 dan merutekan /rest/v1/, /auth/v1/, dan /storage/v1/ ke backend yang sesuai. Hanya container ini yang boleh Anda expose.
  • rest adalah PostgREST. Service ini membaca schema Postgres Anda dan menyajikannya sebagai REST API. Tabel baru otomatis menjadi endpoint baru tanpa kode tambahan.
  • auth adalah GoTrue. Service ini menerbitkan JSON web token (JWT) untuk mengidentifikasi user Anda.
  • storage dan imgproxy menangani upload file dan pengubahan ukuran gambar.
  • realtime melakukan streaming perubahan database melalui websocket.
  • studio dan meta adalah dashboard dan admin API yang mendukungnya.
  • functions adalah edge runtime berbasis Deno, sedangkan supavisor adalah connection pooler untuk Postgres.

Log dan analytics (Logflare serta vector) dikeluarkan dari file Compose default pada June 2026. Keduanya sekarang tersedia sebagai file override opsional yang Anda aktifkan dengan sh run.sh config add logs. Ini menggunakan layering file Compose yang sama seperti yang dijelaskan dalam menjalankan satu stack dari beberapa file Compose.

Daftar tersebut menjelaskan angka resource di bawah ini. Anda tidak hanya menjalankan database. Anda menjalankan database serta sepuluh service pendukung.

Ukuran Server: rencanakan 8 GB RAM

Stack menggunakan sekitar 2.5 hingga 3 GB memori resident saat idle pada instalasi baru per Juli 2026, sebelum data atau trafik Anda ditambahkan. Dalam pengukuran tersebut, service analytics dan proses Studio Node.js merupakan dua konsumen memori tunggal terbesar. Analytics tidak lagi menjadi bagian dari stack default, sehingga hanya menggunakan memori jika Anda mengaktifkan override logs. Server dengan 2 GB RAM akan menjalankan container, lalu salah satunya dihentikan oleh kernel karena kehabisan memori. Gejalanya adalah container terus-menerus melakukan restart dengan exit code 137. Dokumentasi self-hosting Supabase, yang diperiksa pada Oktober 2026, mencantumkan 4 GB RAM, 2 core CPU, dan 40 GB SSD sebagai minimum, serta 8 GB RAM, 4 core, dan 80 GB sebagai konfigurasi yang direkomendasikan.

Gunakan 8 GB RAM dan 4 vCPU untuk layanan yang Anda andalkan. RAM 4 GB cukup untuk instance pengembangan pribadi jika Anda menerima bahwa query berat dan sesi Studio yang berjalan bersamaan akan lambat. Kapasitas disk juga penting karena Postgres, volume penyimpanan, dan data log jika Anda mengaktifkan logs, semuanya berada di bawah direktori project. Mulailah dengan 40 GB dan pantau penggunaannya. Menghitung kebutuhan service sebelum memilih paket adalah kebiasaan yang layak dipertahankan untuk segala sesuatu yang Anda self-host, karena PhotoPrism dan Immich juga memiliki kebutuhan minimum RAM yang nyata: halaman quick start Immich, yang diperiksa pada Oktober 2026, meminta setidaknya 6 GB RAM dan 2 core CPU. Jika spesifikasi tersebut masih lebih besar daripada kebutuhan project Anda, bandingkan dengan isi sebenarnya dari paket cloud gratis Supabase, karena aplikasi kecil yang tetap menggunakan kurang dari 500 MB dan tidak pernah idle selama seminggu mungkin dapat berjalan di sana tanpa biaya.

Instalasi: clone repositori resmi

Metode yang didukung menyalin direktori docker dari repositori utama ke direktori proyek Anda sendiri. Pemisahan ini penting karena git pull berikutnya tidak akan menimpa .env Anda.

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 mengunduh beberapa gigabyte image. Proses ini harus berakhir dengan setiap service berstatus Pulled. Error manifest unknown di sini berarti tag image yang ditetapkan telah dihapus di upstream. Solusinya adalah mengambil salinan repositori yang lebih baru, bukan mengubah tag secara manual.

Rahasia yang harus Anda ubah sebelum memulai untuk pertama kali

Lakukan ini sebelum memulai stack, bukan setelahnya. Beberapa nilai ini ditulis ke dalam data saat boot pertama. Jika diubah kemudian, database harus direset.

Repository menyediakan generator yang menghasilkan setiap nilai dengan benar, termasuk dua API key yang harus ditandatangani dengan JWT secret baru Anda.

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

Skrip tersebut menulis nilai baru untuk JWT_SECRET, ANON_KEY, SERVICE_ROLE_KEY, SECRET_KEY_BASE, REALTIME_DB_ENC_KEY, VAULT_ENC_KEY, PG_META_CRYPTO_KEY, token Logflare, protocol key S3, dan MINIO_ROOT_PASSWORD ke dalam .env. Sejak October 2026, skrip tersebut juga menulis nilai acak untuk POSTGRES_PASSWORD dan DASHBOARD_PASSWORD. Skrip ini memerlukan openssl, yang tersedia pada image Ubuntu normal mana pun. Karena sekarang skrip tersebut juga menulis ulang password database, jalankan dengan --update-env hanya sebelum start pertama. Jangan jalankan pada stack yang sudah berisi data.

Dua nilai berikut masih perlu diperiksa secara manual di .env:

  • POSTGRES_PASSWORD. Skrip mengisinya dengan hex acak, dan nilai ini aman. Jika Anda menggantinya dengan nilai sendiri, gunakan hanya huruf dan angka. Tanda baca di sini merusak connection string yang dibuat beberapa service dengan menggabungkan string. Kegagalannya tampak seperti error autentikasi, bukan error parsing. Akibatnya, pemeriksaan sering dilakukan di tempat yang salah.
  • DASHBOARD_USERNAME dan DASHBOARD_PASSWORD. Keduanya adalah kredensial basic authentication untuk Studio. Skrip menetapkan password acak, tetapi membiarkan username pada nilai default supabase. Password default yang disediakan adalah this_password_is_insecure_and_should_be_updated. Jadi, jika Anda melewati skrip tersebut, ubah password itu sekarang.

Pahami mengapa ANON_KEY dan SERVICE_ROLE_KEY tidak dapat dibuat sembarangan. Keduanya adalah JWT yang ditandatangani dengan JWT_SECRET. Gateway hanya menerima key yang persis sama dengan yang ada di .env. Service di belakang gateway memverifikasi tanda tangan terhadap JWT_SECRET. Karena itu, key yang tidak cocok akan ditolak dengan HTTP 401. Envoy gateway default menjawab 401 Unauthorized. Kong override saat ini juga menjawab {"message":"Unauthorized"}; override tersebut menjalankan Kong 3.9. Instalasi sebelum March 2026 menjalankan Kong 2.8 dan menjawab {"message":"Invalid authentication credentials"}. Ini adalah kegagalan self-hosting yang paling umum: operator mengubah JWT_SECRET, tetapi tetap menggunakan key demo. Selalu buat ketiganya secara bersamaan.

Perlakukan SERVICE_ROLE_KEY seperti password root. Nilai ini melewati row level security sepenuhnya. Nilai ini hanya boleh berada di kode sisi server dan tidak boleh berada di tempat lain.

Atur SITE_URL ke alamat aplikasi Anda. Atur API_EXTERNAL_URL ke alamat publik API dengan /auth/v1 di bagian akhir, misalnya https://supabase.example.com/auth/v1. Atur SUPABASE_PUBLIC_URL ke alamat publik yang sama tanpa path. Auth membuat link konfirmasi email dan callback OAuth dari nilai-nilai tersebut. Jika dibiarkan pada nilai default localhost, semua pengguna Anda akan diarahkan ke mesin mereka sendiri.

Kemudian periksa nilai yang telah Anda tetapkan:

sh run.sh secrets

Jalankan dan pastikan statusnya sehat

sh run.sh start
docker compose ps

run.sh start membungkus docker compose up -d --wait, sehingga perintah tersebut tidak selesai sampai pemeriksaan kesehatan berhasil. Setiap service harus menampilkan running (healthy) atau running. Boot pertama memerlukan waktu dua hingga empat menit karena Postgres menjalankan skrip inisialisasinya sebelum komponen lain dapat terhubung.

Jika sebuah container terus melakukan restart, baca log-nya berdasarkan nama service:

docker compose logs db
docker compose logs auth

Studio tersedia pada port 8000, lalu akan meminta username dan password dashboard yang Anda tetapkan.

Jangan menempatkan port 8000 di Internet publik

Gateway pada port 8000 menggunakan HTTP biasa. Setiap kunci API dan setiap kata sandi pengguna melintasi jaringan dalam teks biasa. Kredensial Studio menggunakan autentikasi dasar, yang hanya berupa pengodean base64, bukan enkripsi.

Tempatkan reverse proxy di depannya, lakukan terminasi TLS (transport layer security) di sana, lalu bind gateway ke alamat loopback agar tidak dapat diakses oleh komponen lain. Dalam docker-compose.yml, baris port di bawah service api-gw menjadi 127.0.0.1:${API_GW_HTTP_PORT:-${KONG_HTTP_PORT:-8000}}:8000/tcp, lalu proxy meneruskan koneksi ke port tersebut. Pada instalasi sebelum perpindahan ke Envoy pada August 2026, baris port yang sama berada di bawah service bernama kong. Traefik di depan beberapa aplikasi Compose menjelaskan bagian sertifikat. Proxy yang sama nantinya juga berada di depan semua layanan lain pada server tersebut, mulai dari stack ini hingga sesuatu yang tidak terlalu serius seperti library Jellyfin yang dibangun ulang sebagai toko video era 90-an. Masing-masing layanan memerlukan hostname, bukan port terbuka tambahan. Jika dashboard hanya digunakan oleh Anda, lewati proxy dan akses port loopback melalui SSH tunnel. Pendekatan yang sama digunakan oleh open-kritt yang di-host sendiri untuk sepenuhnya menjauhkan antarmuka pemindainya dari Internet publik.

Tutup port lainnya di firewall juga, karena Docker memublikasikan port dengan menulis aturan iptables sendiri yang tidak terlihat oleh konfigurasi ufw sederhana. Jebakan tersebut dijelaskan dalam alasan container Docker mengabaikan aturan ufw Anda.

Cadangkan database, bukan direktorinya

Data Postgres berada di bind mount pada ./volumes/db/data. Menyalin direktori tersebut saat container berjalan menghasilkan salinan yang tidak konsisten, karena Postgres menyangga operasi penulisan dan file di disk hanya konsisten pada checkpoint. Proses pemulihan biasanya tetap berhasil, tetapi terkadang transaksi terakhir hilang tanpa pesan apa pun. Ini adalah mode kegagalan terburuk untuk sebuah cadangan.

Gunakan dump. pg_dumpall berjalan di dalam container dan menghasilkan snapshot yang konsisten:

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

Pastikan file tidak kosong sebelum menganggapnya valid. Selanjutnya, kirim dump tersebut secara terjadwal ke luar server. Inilah fungsi backup terenkripsi di lokasi terpisah dengan restic. Dump terjadwal yang gagal tanpa pesan tidak dapat dibedakan dari tidak adanya backup sama sekali. Karena itu, minta job cron atau systemd mengirimkan peringatan ke ponsel Anda saat selesai dengan kode non-zero. Cadangkan .env pada waktu yang sama. Jika JWT_SECRET hilang, setiap token yang telah diterbitkan menjadi tidak valid dan setiap secret terenkripsi yang tersimpan tidak dapat dibaca.

File yang diunggah berada di ./volumes/storage. File tersebut adalah file biasa, sehingga dapat disalin secara langsung.

Perbarui tanpa kehilangan data

Supabase menetapkan versi image di docker-compose.yml, sehingga tidak ada yang berubah sampai Anda mengubahnya. Penetapan versi ini layak diterapkan pada stack apa pun yang Anda rakit secara manual. Karena itu, relay RustDesk yang di-host sendiri menetapkan versi kedua image servernya, alih-alih mengikuti tag yang terus berubah. Upgrade seharusnya dilakukan pada waktu yang Anda pilih dan ketika Anda memiliki waktu untuk menanganinya. Selalu buat dump terlebih dahulu.

docker compose pull
sh run.sh recreate

recreate menghentikan stack, lalu menjalankannya kembali menggunakan image baru. Data Anda tetap ada karena disimpan dalam bind mount pada host, bukan di dalam container. Baca CHANGELOG.md di repository sebelum melakukan lompatan versi mayor, karena upgrade mayor Postgres merupakan langkah terpisah yang tidak dilakukan oleh recreate. Postgres 17 telah menjadi versi default sejak June 2026. Instalasi yang sudah menggunakan Postgres 15 dapat dipindahkan ke versi tersebut dengan sudo bash utils/upgrade-pg17.sh. Perintah ini menggunakan pg_upgrade untuk memigrasikan data di tempat dan meminta konfirmasi pada setiap langkah mayor. Semua container harus berjalan. Selain itu, ruang disk kosong harus berukuran setidaknya dua kali ukuran database Anda ditambah 5 GB. Supabase tetap merekomendasikan agar Anda membuat backup independen sendiri sebelum memulai.

Untuk menerapkan perubahan pada file Compose itu sendiri, jalankan sh update.sh dari direktori project. Anda juga dapat menjalankan sh update.sh --dry-run terlebih dahulu untuk melihat perubahan yang akan terjadi. Perintah ini menggabungkan file upstream dengan perubahan Anda sendiri. Perintah ini tidak pernah menimpa nilai yang sudah ada di .env, tetapi hanya menambahkan key baru. Konfigurasi Anda diarsipkan di backups/ sebelum ditulis, tetapi database tidak diarsipkan. Instalasi tanpa file .supabase-version memerlukan --from dan release yang digunakan saat instalasi dimulai. Hal ini terutama penting untuk release August 2026, yang mengganti service kong dengan api-gw dan memerlukan pembaruan docker-compose.yml. Cara manual tetap dapat digunakan. Clone repository upstream sekali lagi, lalu salin direktori docker ke project Anda. Jangan sampai .env tertimpa.

Reset penuh akan menghapus semuanya, termasuk database, dan mengembalikan .env ke default. Konfigurasi lama disimpan sebagai .env.old. Reset ini menggunakan script terpisah dan meminta konfirmasi:

sh reset.sh

FAQ

Mengapa panggilan API saya mengembalikan "Invalid authentication credentials"?

Pesan persis tersebut berasal dari Kong 2.8, yaitu gateway dalam stack pada instalasi sebelum Maret 2026. Gateway Envoy default dan override Kong saat ini, yang menjalankan Kong 3.9, melaporkan masalah yang sama sebagai 401 biasa Unauthorized. Bagaimanapun, key yang Anda kirim tidak cocok dengan ANON_KEY atau SERVICE_ROLE_KEY dalam .env, atau key tersebut tidak ditandatangani dengan JWT_SECRET yang saat ini terdapat dalam .env. Pada stack yang belum pernah menyimpan data, buat ulang ketiganya secara bersamaan dengan sh utils/generate-keys.sh --update-env. Pada stack yang sedang berjalan, jalankan script tanpa flag tersebut dan jawab no agar script hanya menampilkan nilai baru. Salin JWT_SECRET, ANON_KEY, dan SERVICE_ROLE_KEY ke dalam .env secara manual, lalu jangan ubah POSTGRES_PASSWORD. Setelah itu, jalankan sh run.sh recreate agar service membaca nilai baru.

Dapatkah saya menjalankan Supabase yang di-host sendiri pada VPS 2 GB?

Tidak secara andal. Dokumentasi self-hosting Supabase mencantumkan RAM 4 GB sebagai minimum per Oktober 2026. Stack menggunakan hampir 3 GB saat idle per Juli 2026 dalam pengukuran yang mencakup service logging, yang sekarang bersifat opsional. Server 2 GB akan kehilangan container karena out of memory killer, dan Anda akan melihat exit code 137 dalam docker compose ps. Gunakan 8 GB untuk produksi. Anggap 4 GB sebagai batas minimum untuk pengembangan pribadi.

Apakah Supabase yang di-host sendiri menyertakan edge functions?

Ya. File Compose menyertakan runtime functions berbasis Deno. Runtime tersebut menjalankan apa pun yang Anda tempatkan di bawah ./volumes/functions. Runtime ini tidak menyertakan jaringan deployment global milik platform hosted. Karena itu, functions Anda berjalan pada satu server dan satu lokasi.

Bagaimana cara terhubung langsung ke database Postgres?

Gunakan docker exec -it supabase-db psql -U postgres untuk membuka shell interaktif langsung pada server. Untuk client eksternal, terhubung melalui Supavisor pada port 5432 menggunakan user postgres.<POOLER_TENANT_ID> dan POSTGRES_PASSWORD Anda. Jangan membuka port tersebut ke Internet. Akses port itu melalui VPN atau tunnel SSH.

Mengapa email konfirmasi auth saya mengarah ke localhost?

SITE_URL dan API_EXTERNAL_URL dalam .env masih menggunakan nilai default. auth service membuat setiap tautan konfirmasi dan reset password berdasarkan kedua nilai tersebut. Karena itu, service mengirimkan alamat yang dikonfigurasikan untuk digunakan. Tetapkan keduanya ke URL publik yang sebenarnya, lalu buat ulang stack.

Apakah artikel ini bermanfaat?