Cara Self-Host Supabase di VPS dengan Docker
Pelajari cara menjalankan stack Docker Supabase resmi di VPS, mengganti secret demo yang terbuka, memahami 14 layanan, kebutuhan RAM, backup, dan pembaruan.
Hal yang Anda bangun
Menjalankan Supabase secara mandiri berarti menjalankan stack Docker Compose resmi di server Anda sendiri: Postgres, REST API di depannya, layanan autentikasi, penyimpanan file, websocket realtime, dan dasbor Studio. Anda meng-clone satu repositori, mengedit satu file .env, lalu menjalankan sekitar empat belas 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 repositori. Stack yang dijalankan dengan nilai default tersebut dapat diakses oleh siapa pun yang menemukannya. Panduan ini menjelaskan secret yang harus Anda ganti, fungsi setiap layanan, jumlah memori yang benar-benar dibutuhkan stack, dan cara memperbaruinya tanpa menghapus database.
Jika Compose masih baru bagi Anda, baca Dasar-dasar Docker Compose di VPS terlebih dahulu. Semua langkah di bawah ini mengasumsikan docker compose version sudah menampilkan versi.
Isi sebenarnya dalam stack
Supabase bukan satu program. File Compose memulai sekumpulan layanan terpisah dalam satu jaringan. Dengan mengetahui fungsi setiap layanan, Anda dapat mendiagnosis masalah tanpa harus menelusuri banyak nama container.
dbadalah PostgreSQL dengan ekstensi Supabase yang dimuat. Semua layanan lain berkomunikasi dengannya. Jika container ini tidak sehat, layanan lainnya juga gagal.kongadalah gateway API. Layanan ini mendengarkan pada port 8000 dan merutekan/rest/v1/,/auth/v1/, serta/storage/v1/ke backend yang sesuai. Hanya container ini yang boleh Anda ekspos.restadalah PostgREST. Layanan ini membaca skema Postgres Anda dan menyediakannya sebagai REST API. Dengan demikian, tabel baru menjadi endpoint baru tanpa memerlukan kode.authadalah GoTrue. Layanan ini menerbitkan JSON web token (JWT) yang mengidentifikasi pengguna Anda.storagedanimgproxymenangani upload file dan pengubahan ukuran gambar.realtimemengalirkan perubahan database melalui websocket.studiodanmetaadalah dasbor dan API admin yang mendukungnya.analytics(Logflare) danvectormengumpulkan log, sedangkansupavisoradalah pool koneksi Postgres.
Daftar tersebut menjelaskan angka resource di bawah ini. Anda tidak hanya menjalankan database. Anda menjalankan database beserta selusin layanan pendukung.
Ukuran: rencanakan RAM sebesar 8 GB
Stack menggunakan sekitar 2.5 hingga 3 GB memori resident saat tidak aktif pada instalasi baru, per Juli 2026, sebelum data atau traffic Anda ditambahkan. Layanan analytics dan proses Studio Node.js merupakan dua pengguna sumber daya terbesar. Server dengan RAM 2 GB akan memulai container, lalu kernel akan menghentikan salah satunya karena kehabisan memori, biasanya analytics atau db. Gejalanya adalah container terus-menerus melakukan restart dengan exit code 137.
Gunakan RAM 8 GB 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 semuanya berada di bawah direktori project. Mulai dengan 40 GB dan pantau penggunaannya.
Instal: kloning repositori resmi
Metode yang didukung menyalin direktori docker dari repositori utama ke direktori proyek milik Anda. Pemisahan ini penting karena git pull di kemudian hari tidak dapat 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 pulldocker compose pull mengunduh beberapa gigabita image. Proses ini harus berakhir dengan setiap layanan ditandai Pulled. Error manifest unknown di sini berarti tag image yang ditetapkan telah dihapus di upstream. Solusinya adalah mengambil salinan repositori yang lebih baru, bukan mengedit 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, sehingga mengubahnya nanti berarti mengatur ulang database.
Repositori ini menyediakan generator yang menghasilkan semua nilai dengan benar, termasuk dua API key yang harus ditandatangani dengan secret JWT baru Anda.
sh utils/generate-keys.sh --update-envSkrip 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 serta token Logflare ke dalam .env. Skrip ini memerlukan openssl, yang tersedia pada image Ubuntu normal mana pun.
Ada dua nilai yang tidak diatur oleh skrip tersebut dan harus Anda edit secara manual di .env:
POSTGRES_PASSWORD. Gunakan huruf dan digit saja. Tanda baca di sini merusak connection string yang dibuat beberapa layanan dengan menggabungkan string. Kegagalan ini terlihat seperti error autentikasi, bukan error parsing, sehingga orang biasanya mencari penyebab di tempat yang salah.DASHBOARD_USERNAMEdanDASHBOARD_PASSWORD. Keduanya adalah kredensial autentikasi dasar untuk Studio. Password default yang disertakan secara harfiah adalahthis_password_is_insecure_and_should_be_updated.
Pahami alasan ANON_KEY dan SERVICE_ROLE_KEY tidak boleh dibuat secara sembarang. Keduanya adalah JWT yang ditandatangani dengan JWT_SECRET. Gateway memverifikasi tanda tangan tersebut pada setiap request, sehingga key yang tidak cocok dengan secret Anda ditolak dengan {"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 sepenuhnya melewati row level security. Nilai ini hanya boleh ditempatkan dalam kode sisi server dan di tempat lain tidak boleh.
Atur SITE_URL dan API_EXTERNAL_URL ke alamat yang benar-benar akan diakses pengguna Anda, misalnya https://supabase.example.com. Auth membuat tautan konfirmasi email dan callback OAuth dari nilai tersebut. Jika tetap menggunakan http://localhost:8000, setiap pengguna akan diarahkan ke mesin mereka sendiri.
Kemudian periksa nilai yang Anda miliki:
sh run.sh secretsJalankan dan konfirmasikan bahwa kondisinya sehat
sh run.sh start
docker compose psrun.sh start membungkus docker compose up -d --wait, sehingga perintah ini tidak mengembalikan hasil sampai pemeriksaan kesehatan berhasil. Setiap layanan 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 dimulai ulang, baca log-nya berdasarkan nama layanan:
docker compose logs db
docker compose logs authStudio tersedia pada port 8000, lalu akan meminta nama pengguna dan kata sandi dashboard yang Anda tetapkan.
Jangan mengekspos port 8000 ke internet publik
Kong pada port 8000 menggunakan HTTP biasa. Setiap kunci API dan setiap kata sandi pengguna dikirim melalui jaringan dalam teks biasa. Kredensial Studio menggunakan autentikasi dasar, yaitu pengodean base64, bukan enkripsi.
Tempatkan proxy terbalik di depannya. Hentikan TLS (keamanan lapisan transport) di proxy tersebut. Ikat Kong ke alamat loopback agar tidak dapat diakses oleh pihak lain. Dalam docker-compose.yml, pemetaan port kong menjadi 127.0.0.1:8000:8000, lalu proxy meneruskan permintaan ke port tersebut. Traefik di depan beberapa aplikasi Compose menjelaskan konfigurasi sertifikat.
Tutup port lainnya di firewall. Docker memublikasikan port dengan menulis aturan iptables sendiri, sehingga konfigurasi ufw yang sederhana tidak pernah melihatnya. Jebakan ini dijelaskan dalam mengapa container Docker mengabaikan aturan ufw Anda.
Cadangkan basis data, bukan direktorinya
Data Postgres berada dalam bind mount di ./volumes/db/data. Menyalin direktori tersebut saat container berjalan menghasilkan salinan yang tidak utuh, karena Postgres menyangga penulisan dan file pada disk hanya konsisten saat checkpoint. Memulihkannya biasanya berhasil, tetapi terkadang transaksi terakhir hilang tanpa diketahui. Ini adalah mode kegagalan terburuk untuk pencadangan.
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).sqlPastikan file tersebut tidak kosong sebelum mempercayainya. Selanjutnya, kirim dump itu ke luar server secara terjadwal. Itulah fungsi pencadangan terenkripsi di luar lokasi dengan restic. Cadangkan .env pada waktu yang sama. Kehilangan JWT_SECRET berarti semua token yang telah diterbitkan menjadi tidak valid dan semua rahasia terenkripsi yang tersimpan tidak dapat dibaca.
File yang diunggah berada di ./volumes/storage. File tersebut adalah file biasa, jadi penyalinan biasa sudah memadai.
Memperbarui tanpa kehilangan data
Supabase menetapkan versi image di docker-compose.yml, sehingga tidak ada yang berubah sampai Anda memperbaruinya. Selalu buat dump terlebih dahulu.
docker compose pull
sh run.sh recreaterecreate menghentikan stack, lalu menjalankannya kembali dengan image baru. Data Anda tetap ada karena data tersebut berada di bind mount pada host, bukan di dalam container. Baca CHANGELOG.md di repositori sebelum melakukan lompatan versi mayor, karena upgrade mayor Postgres tidak dilakukan secara otomatis dan memerlukan dump serta restore.
Untuk menerapkan perubahan pada file Compose itu sendiri, clone kembali repositori upstream dan salin direktori docker ke project Anda. Jangan sampai .env tertimpa.
Reset penuh, yang menghapus semuanya termasuk database, menggunakan skrip terpisah dan meminta konfirmasi:
sh reset.shFAQ
Mengapa panggilan API saya mengembalikan "Invalid authentication credentials"?
ANON_KEY atau SERVICE_ROLE_KEY Anda tidak ditandatangani dengan JWT_SECRET yang saat ini berada di .env. Gateway memverifikasi tanda tangan pada setiap permintaan dan menolak ketidakcocokan. Buat ulang ketiganya secara bersamaan dengan sh utils/generate-keys.sh --update-env, lalu jalankan sh run.sh recreate agar layanan membaca nilai baru.
Apakah saya dapat menjalankan Supabase yang di-host sendiri pada VPS 2 GB?
Tidak secara andal. Stack ini menggunakan hampir 3 GB saat tidak melakukan aktivitas, per Juli 2026, karena menjalankan sekitar empat belas layanan. Akibatnya, server 2 GB kehilangan container karena out of memory killer, dan Anda melihat exit code 137 di docker compose ps. Gunakan 8 GB untuk production dan anggap 4 GB sebagai kapasitas minimum untuk pengembangan pribadi.
Apakah Supabase yang di-host sendiri menyertakan edge functions?
Ya. File Compose menyertakan runtime functions berbasis Deno dan menyajikan apa pun yang Anda tempatkan di bawah ./volumes/functions. Stack ini tidak menyertakan jaringan deployment global milik platform hosted. Karena itu, functions Anda berjalan pada satu server di satu lokasi.
Bagaimana cara terhubung langsung ke database Postgres?
Gunakan docker exec -it supabase-db psql -U postgres untuk membuka shell interaktif pada server itu sendiri. Untuk client eksternal, hubungkan melalui Supavisor pada port 5432 dengan user postgres.<POOLER_TENANT_ID> dan POSTGRES_PASSWORD Anda. Jangan membuka port tersebut ke internet. Akses melalui VPN atau tunnel SSH.
Mengapa email konfirmasi auth saya tertaut ke localhost?
SITE_URL dan API_EXTERNAL_URL di .env masih menggunakan nilai default. Layanan auth membangun setiap tautan konfirmasi dan reset password dari kedua nilai tersebut. Akibatnya, layanan mengirim alamat yang dikonfigurasikan. Tetapkan keduanya ke URL publik Anda yang sebenarnya, lalu buat ulang stack.