SSD Nodes Learn Hosting plans →
指南 Matt Connor作者: Matt Connor · 已更新 2026-08-27

VPS 上用 Docker 自行代管 Supabase

學會在自有伺服器執行官方 Supabase Docker stack:替換公開示範 secrets、了解 14 個服務、預留 8 GB RAM,並安全備份與更新。

建置內容

自行代管 Supabase,表示在自己的伺服器上執行官方 Docker Compose stack,其中包含 Postgres、位於其前端的 REST API、驗證服務、檔案儲存、即時 WebSocket,以及 Studio 儀表板。您只需複製一個 repository、編輯一個 .env 檔案,然後啟動約 14 個 containers;這些元件會共同運作,形成一個由您控管的 Supabase 專案。

安裝步驟很短。最常出問題的是 .env 檔案。該檔案附帶 repository 中公開的示範 secrets,使用這些預設值啟動的 stack,任何找到它的人都能存取。本指南說明必須替換的 secrets、各項服務的用途、stack 實際需要多少記憶體,以及如何在不刪除資料庫的情況下更新 stack。

如果您不熟悉 Compose,請先閱讀 VPS 上的 Docker Compose 基礎。以下所有步驟都假設執行 docker compose version 已能顯示版本。

堆疊實際包含的元件

Supabase 不是單一程式。Compose 檔案會在同一個網路上啟動一組獨立服務。了解各服務的用途後,才能將一長串容器名稱轉化為可供除錯的資訊。

  • db 是載入 Supabase 擴充功能的 PostgreSQL。其他所有服務都會與它通訊。如果此容器狀態異常,其他服務也會全部失敗。
  • kong 是 API gateway。它監聽 port 8000,並將 /rest/v1//auth/v1//storage/v1/ 路由至正確的後端。這是唯一應該對外公開的容器。
  • rest 是 PostgREST。它讀取 Postgres schema,並將其提供為 REST API,因此新增資料表後,無須撰寫程式碼即可產生新的 endpoint。
  • auth 是 GoTrue。它會簽發用來識別使用者的 JSON web token(JWT)。
  • storageimgproxy 負責處理檔案上傳與影像調整大小。
  • realtime 會透過 websockets 串流資料庫變更。
  • studiometa 分別是 dashboard,以及其背後的 admin API。
  • analytics(Logflare)和 vector 會收集日誌,而 supavisor 是 PostgreSQL connection pooler。

這份清單說明了下方資源數值的由來。你執行的不只是資料庫,而是資料庫加上十多個支援服務。

容量規劃:預留 8 GB RAM

截至 July 2026,在全新安裝且尚未計入自有資料或網路流量時,這套服務堆疊閒置時約使用 2.5 至 3 GB 的常駐記憶體。analytics service 與 Studio Node.js process 是使用記憶體最多的兩個單一元件。2 GB 伺服器會先啟動容器,接著由 kernel out-of-memory killer 終止其中一個,通常是 analyticsdb。常見症狀是容器持續重新啟動,並以 exit code 137 結束。

對任何依賴這套服務的環境,請配置 8 GB RAM 與 4 vCPU。若能接受重型查詢與 Studio 工作階段同時執行時速度緩慢,4 GB 可用於單人開發環境。磁碟空間同樣重要,因為 Postgres、儲存磁碟區與日誌資料都位於 project directory 下。先配置 40 GB,再持續監控使用量。選擇方案前先盤點服務,是自架任何服務都值得保留的習慣,因為 PhotoPrism 與 Immich 的實際記憶體最低需求,遠高於其快速入門頁面所暗示的容量。

安裝:複製官方儲存庫

支援的方式是將主要儲存庫中的 docker 目錄複製到您自行建立的專案目錄。這種分離很重要,因為後續執行 git pull 時,不會覆寫您的 .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 會下載數 GB 的映像檔。完成後,每個服務都應標示為 Pulled。如果這裡出現 manifest unknown 錯誤,表示上游已移除指定的映像檔標籤。此時應重新拉取較新的儲存庫版本,不要手動修改標籤。

首次啟動前必須變更的 secret

請在啟動 stack 前完成這些設定,不要等到啟動後才處理。其中數個值會在首次啟動時寫入資料,因此之後才變更就必須重設資料庫。

repository 提供一個 generator,可正確產生所有值,包括必須使用新的 JWT secret 簽署的兩個 API key。

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

該 script 會將 JWT_SECRETANON_KEYSERVICE_ROLE_KEYSECRET_KEY_BASEREALTIME_DB_ENC_KEYVAULT_ENC_KEYPG_META_CRYPTO_KEY 和 Logflare tokens 的新值寫入 .env。它需要 openssl;任何一般的 Ubuntu image 都已提供此工具。

以下兩個值不會由它設定,必須在 .env 中手動編輯:

  • POSTGRES_PASSWORD。只能使用字母與數字。此處若包含標點符號,會破壞數個服務透過串接字串建立的 connection strings。錯誤看起來會像 authentication error,而不是 parsing error,導致排查方向錯誤。
  • DASHBOARD_USERNAMEDASHBOARD_PASSWORD。這是 Studio 的 basic authentication credentials。預設密碼實際上就是 this_password_is_insecure_and_should_be_updated

請理解為何不能自行編造 ANON_KEYSERVICE_ROLE_KEY。兩者都是使用 JWT_SECRET 簽署的 JWT。gateway 會在每個 request 上驗證該 signature,因此與你的 secret 不相符的 key 會被 {"message":"Invalid authentication credentials"} 拒絕。這是 self-hosting 最常見的失敗原因:operator 變更了 JWT_SECRET,卻保留 demo keys。請務必一併產生這三個值。

請將 SERVICE_ROLE_KEY 視同 root password。它會完全繞過 row level security。只能放在 server side code 中,不得放在其他位置。

SITE_URLAPI_EXTERNAL_URL 設為使用者實際連線的網址,例如 https://supabase.example.com。Auth 會根據這些值建立 email confirmation 與 OAuth callback links。若保留為 http://localhost:8000,所有使用者都會被導向各自的電腦。

接著檢查目前的設定:

sh run.sh secrets

啟動並確認服務狀態正常

sh run.sh start
docker compose ps

run.sh start 包裝 docker compose up -d --wait,因此會持續等待,直到健康檢查通過。每個服務都應顯示 running (healthy)running。首次啟動需要 2 到 4 分鐘,因為 Postgres 會先執行初始化指令碼,其他服務必須等到完成後才能連線。

如果容器持續重新啟動,請依服務名稱查看其日誌:

docker compose logs db
docker compose logs auth

Studio 會使用 8000 埠,並要求輸入您設定的 dashboard 使用者名稱與密碼。

不要將連接埠 8000 暴露在公用網際網路上

Kong 在 8000 上使用純 HTTP。每組 API key 與使用者密碼都會以明文穿過網路;Studio 憑證採用基本驗證,其本質是 base64 編碼,而非加密。

在前方配置反向代理,並在該處終止 TLS(傳輸層安全性)。同時將 Kong 綁定至 loopback 位址,讓其他來源無法連線。在 docker-compose.yml 中,kong 連接埠映射會變成 127.0.0.1:8000:8000,代理再將請求轉送至該位址。在多個 Compose 應用程式前配置 Traefik 說明憑證相關設定。

也要在防火牆封鎖其餘連接埠,因為 Docker 會自行寫入 iptables 規則來發布連接埠,單純的 ufw 設定通常無法攔截這些流量。Docker 容器為何會忽略 ufw 規則 說明了這個常見陷阱。

備份資料庫,不要備份目錄

Postgres 資料位於 ./volumes/db/data 的 bind mount 中。容器執行期間複製該目錄會產生不完整的副本,因為 Postgres 會緩衝寫入,而磁碟上的檔案只有在 checkpoint 時才會保持一致。還原這類副本通常可以成功,但有時會在沒有明顯錯誤的情況下遺失最後幾筆交易。這是備份最不應出現的失敗模式。

請改用 dump。pg_dumpall 會在容器內執行,並產生一致的快照:

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

確認檔案不是空的,再信任該備份。接著依排程將這些 dump 傳送到伺服器外部,這就是使用 restic 進行加密的異地備份的用途。同時備份 .env。遺失 JWT_SECRET 會使所有已簽發的 token 失效,且無法讀取所有已儲存的加密 secret。

上傳的檔案位於 ./volumes/storage,這些檔案是一般檔案,因此直接複製即可。

更新而不遺失資料

Supabase 會在 docker-compose.yml 中固定映像檔版本,因此除非手動更新,版本不會自行變更。無論組建哪種手動管理的堆疊,都值得採用版本固定;因此 自架的 RustDesk relay 會固定其兩個伺服器映像檔的版本,而不是追蹤會變動的標籤:升級應該在你安排好時間的早晨主動執行。每次都要先建立 dump。

docker compose pull
sh run.sh recreate

recreate 會停止堆疊,並使用新的映像重新啟動。資料仍會保留,因為資料位於主機上的 bind mount 中,而不是容器內。進行主要版本升級前,請先閱讀儲存庫中的 CHANGELOG.md,因為 PostgreSQL 主要版本升級不會自動執行,必須先建立傾印,再進行還原。

若要套用 Compose 檔案本身的變更,請再次複製上游儲存庫,並將其中的 docker 目錄複製到專案中,同時注意不要覆寫 .env

完整重設會刪除包括資料庫在內的所有內容。這是另一個獨立的 script,執行時會要求確認:

sh reset.sh

FAQ

為什麼我的 API 呼叫會回傳「Invalid authentication credentials」?

您的 ANON_KEYSERVICE_ROLE_KEY 並未使用目前位於 .envJWT_SECRET 進行簽署。閘道會驗證每個請求的簽章,簽章不相符時便會拒絕請求。使用 sh utils/generate-keys.sh --update-env 重新產生這三項內容,然後執行 sh run.sh recreate,讓服務讀取新的值。

我可以在 2 GB VPS 上執行自架 Supabase 嗎?

無法可靠執行。截至 2026 年 7 月,這套 stack 閒置時即接近 3 GB,因為會執行約 14 個服務。因此,2 GB 主機會因 out of memory killer 而終止容器,並在 docker compose ps 中看到 exit code 137。正式環境請使用 8 GB,單人開發則至少需要 4 GB。

自架 Supabase 是否包含 edge functions?

包含。Compose 檔案包含以 Deno 為基礎的 functions runtime,並會提供您放在 ./volumes/functions 下的內容。它不包含代管平台的全球部署網路,因此您的 functions 只會在單一位置的單一伺服器上執行。

如何直接連線至 Postgres 資料庫?

在伺服器本機使用 docker exec -it supabase-db psql -U postgres 開啟互動式 shell。若使用外部用戶端,請透過 port 5432 連線至 Supavisor,並使用使用者 postgres.<POOLER_TENANT_ID> 與您的 POSTGRES_PASSWORD。不要將該 port 開放至網際網路。請透過 VPN 或 SSH tunnel 連線。

為什麼我的 auth 確認電子郵件會連到 localhost?

.env 中的 SITE_URLAPI_EXTERNAL_URL 仍保留預設值。auth service 會根據這兩個值建立所有確認與密碼重設連結,因此會傳送設定值指定的網址。將兩者設為實際的公開 URL,然後重新建立 stack。