SSD Nodes Learn RAM 8GB — $66/ปี
คู่มือ Matt Connorโดย Matt Connor · อัปเดตเมื่อ 2026-08-01

ติดตั้ง Supabase บน VPS ด้วย Docker แบบโฮสต์เอง

คู่มือรัน official Supabase Docker stack บน VPS ของคุณเอง ครอบคลุม secrets ที่ต้องเปลี่ยน บริการประมาณ 14 รายการ RAM ที่ใช้จริง การสำรองข้อมูล และการอัปเดต

สิ่งที่คุณกำลังสร้าง

การโฮสต์ Supabase ด้วยตนเองหมายถึงการเรียกใช้ Docker Compose stack อย่างเป็นทางการบนเซิร์ฟเวอร์ของคุณเอง ซึ่งประกอบด้วย Postgres, REST API ที่ทำงานอยู่ด้านหน้า, บริการยืนยันตัวตน, พื้นที่จัดเก็บไฟล์, realtime websockets และแดชบอร์ด Studio คุณจะโคลน repository 1 รายการ แก้ไขไฟล์ .env 1 ไฟล์ และเริ่มต้นคอนเทนเนอร์ประมาณ 14 รายการ ซึ่งทำงานร่วมกันเสมือนเป็นโปรเจกต์ Supabase ที่คุณควบคุมเอง

ขั้นตอนติดตั้งใช้เวลาไม่นาน ส่วนที่มักเกิดปัญหาคือไฟล์ .env ไฟล์นี้มาพร้อมกับข้อมูลลับตัวอย่างที่เผยแพร่ใน repository และ stack ที่เริ่มต้นด้วยค่าเริ่มต้นเหล่านี้จะเปิดให้ผู้ที่พบเห็นเข้าถึงได้ คู่มือนี้อธิบายข้อมูลลับที่คุณต้องเปลี่ยน หน้าที่ของแต่ละบริการ ปริมาณหน่วยความจำที่ stack ต้องใช้จริง และวิธีอัปเดตโดยไม่ลบฐานข้อมูลของคุณ

หากคุณยังไม่คุ้นเคยกับ Compose โปรดอ่าน พื้นฐาน Docker Compose บน VPS ก่อน เนื้อหาต่อไปนี้ถือว่า docker compose version แสดงหมายเลขเวอร์ชันได้แล้ว

สิ่งที่สแตกประกอบด้วยจริง

Supabase ไม่ใช่โปรแกรมเดียว ไฟล์ Compose จะเริ่มบริการแยกกันหลายรายการบนเครือข่ายเดียวกัน การทราบว่าบริการแต่ละรายการคืออะไรจะช่วยเปลี่ยนรายชื่อคอนเทนเนอร์จำนวนมากให้เป็นระบบที่คุณสามารถตรวจสอบและแก้ไขปัญหาได้

  • db คือ PostgreSQL ที่โหลดส่วนขยายของ Supabase แล้ว บริการอื่นทั้งหมดจะเชื่อมต่อกับบริการนี้ หากคอนเทนเนอร์นี้ไม่อยู่ในสถานะปกติ บริการอื่นทั้งหมดก็จะทำงานล้มเหลวด้วย
  • kong คือเกตเวย์ API ซึ่งรับฟังการเชื่อมต่อบน port 8000 และกำหนดเส้นทาง /rest/v1/, /auth/v1/ และ /storage/v1/ ไปยัง backend ที่ถูกต้อง นี่คือคอนเทนเนอร์เพียงรายการเดียวที่ควรเปิดให้เข้าถึงจากภายนอก
  • rest คือ PostgREST ซึ่งอ่าน schema ของ Postgres แล้วให้บริการเป็น REST API ดังนั้นการสร้างตารางใหม่จะทำให้เกิด endpoint ใหม่โดยไม่ต้องเขียนโค้ด
  • auth คือ GoTrue ซึ่งออก JSON web tokens (JWT) ที่ใช้ระบุผู้ใช้ของคุณ
  • storage และ imgproxy จัดการการอัปโหลดไฟล์และการปรับขนาดรูปภาพ
  • realtime สตรีมการเปลี่ยนแปลงในฐานข้อมูลผ่าน websockets
  • studio และ meta คือแดชบอร์ดและ admin API ที่อยู่เบื้องหลังแดชบอร์ด
  • analytics (Logflare) และ vector รวบรวม log และ supavisor คือเครื่องมือจัดการ connection pool ของ Postgres

รายการนี้อธิบายว่าเหตุใดค่าทรัพยากรด้านล่างจึงเป็นตัวเลขดังกล่าว คุณไม่ได้ใช้งานเพียงฐานข้อมูล คุณกำลังใช้งานฐานข้อมูลร่วมกับบริการสนับสนุนอีกประมาณหนึ่งโหล

การกำหนดขนาด: วางแผนสำหรับ RAM 8 GB

เมื่อเริ่มต้นติดตั้งใหม่ stack จะใช้หน่วยความจำ resident ประมาณ 2.5 ถึง 3 GB ณ เดือน July 2026 โดยยังไม่รวมข้อมูลหรือ network traffic ของคุณเอง analytics service และโปรเซส Studio Node.js เป็นตัวใช้ทรัพยากรรายใหญ่ที่สุด 2 รายการ เซิร์ฟเวอร์ขนาด 2 GB จะเริ่ม containers แล้ว kernel out of memory killer จะหยุดหนึ่งในนั้น โดยปกติคือ analytics หรือ db อาการคือ container ค้างอยู่ในสถานะ restarting พร้อม exit code 137

จัดสรร RAM 8 GB และ 4 vCPU สำหรับระบบที่ต้องพึ่งพา หากยอมรับว่า heavy query และเซสชัน Studio ที่ทำงานพร้อมกันจะช้า instance สำหรับการพัฒนาคนเดียวสามารถทำงานด้วย 4 GB ได้ พื้นที่ดิสก์ก็สำคัญเช่นกัน เพราะ Postgres, storage volume และ log data ทั้งหมดอยู่ภายใต้ project directory เริ่มต้นที่ 40 GB และ monitor การใช้งานพื้นที่ดังกล่าว

ติดตั้ง: โคลน repository อย่างเป็นทางการ

วิธีที่รองรับจะคัดลอกไดเรกทอรี docker จาก repository หลักไปยังไดเรกทอรีโครงการของคุณเอง การแยกนี้มีความสำคัญ เพราะช่วยป้องกันไม่ให้ 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 จะดาวน์โหลด image หลายกิกะไบต์ คำสั่งควรทำงานจนบริการทุกตัวมีสถานะเป็น Pulled ข้อผิดพลาด manifest unknown ในขั้นตอนนี้หมายความว่า upstream ลบแท็ก image ที่กำหนดไว้แล้ว วิธีแก้คือดึง repository ฉบับใหม่กว่า แทนการแก้แท็กด้วยตนเอง

ความลับที่คุณต้องเปลี่ยนก่อนการเริ่มต้นครั้งแรก

ดำเนินการนี้ก่อนเริ่ม stack ไม่ใช่หลังจากนั้น ค่าหลายรายการจะถูกเขียนลงในข้อมูลเมื่อบูตครั้งแรก ดังนั้นการเปลี่ยนค่าเหล่านี้ภายหลังจะทำให้ต้องรีเซ็ตฐานข้อมูล

repository มี generator ที่สร้างค่าทั้งหมดได้อย่างถูกต้อง รวมถึง API keys 2 รายการที่ต้องลงลายเซ็นด้วย JWT secret ใหม่ของคุณ

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

สคริปต์ดังกล่าวจะเขียนค่าใหม่สำหรับ JWT_SECRET, ANON_KEY, SERVICE_ROLE_KEY, SECRET_KEY_BASE, REALTIME_DB_ENC_KEY, VAULT_ENC_KEY, PG_META_CRYPTO_KEY และ Logflare tokens ลงใน .env โดยต้องใช้ openssl ซึ่งมีอยู่ใน Ubuntu image ปกติทุกชุด

มีค่า 2 รายการที่สคริปต์นี้จะไม่ตั้งค่า และคุณต้องแก้ไขด้วยตนเองใน .env:

  • POSTGRES_PASSWORD ใช้เฉพาะตัวอักษรและตัวเลข เครื่องหมายวรรคตอนในค่านี้จะทำให้ connection strings ที่หลาย services สร้างโดยการนำสตริงมาต่อกันใช้งานไม่ได้ และข้อผิดพลาดจะแสดงเหมือนเป็นปัญหาการยืนยันตัวตน ไม่ใช่ข้อผิดพลาดจากการแยกวิเคราะห์ จึงทำให้ผู้ดูแลระบบมักตรวจสอบผิดจุด
  • DASHBOARD_USERNAME และ DASHBOARD_PASSWORD ค่าเหล่านี้คือข้อมูลรับรองสำหรับ basic authentication ของ Studio รหัสผ่านเริ่มต้นที่ให้มาคือ this_password_is_insecure_and_should_be_updated โดยตรง

ต้องเข้าใจว่าเหตุใดจึงสร้าง ANON_KEY และ SERVICE_ROLE_KEY ขึ้นเองไม่ได้ ทั้งสองค่าเป็น JWTs ที่ลงลายเซ็นด้วย JWT_SECRET gateway จะตรวจสอบลายเซ็นนี้ในทุก request ดังนั้น key ที่ไม่ตรงกับ secret ของคุณจะถูกปฏิเสธด้วย {"message":"Invalid authentication credentials"} นี่คือสาเหตุที่พบบ่อยที่สุดของความล้มเหลวในการ self-hosting ผู้ดูแลระบบเปลี่ยน JWT_SECRET แต่ยังคงใช้ demo keys ต้องสร้างทั้ง 3 ค่าพร้อมกันเสมอ

ปฏิบัติต่อ SERVICE_ROLE_KEY เหมือน root password ค่านี้จะข้ามการรักษาความปลอดภัยระดับแถวโดยสมบูรณ์ ต้องใช้ในโค้ดฝั่ง server เท่านั้น และห้ามใช้ที่อื่น

ตั้งค่า SITE_URL และ API_EXTERNAL_URL เป็น address ที่ผู้ใช้ของคุณจะเข้าถึงจริง เช่น https://supabase.example.com Auth จะสร้างลิงก์ยืนยันอีเมลและลิงก์ callback ของ OAuth จากค่าเหล่านี้ ดังนั้นหากปล่อยไว้เป็น 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 และระบบจะขอชื่อผู้ใช้และรหัสผ่านแดชบอร์ดที่คุณตั้งไว้

อย่าเปิดพอร์ต 8000 สู่อินเทอร์เน็ตสาธารณะ

Kong ที่พอร์ต 8000 ใช้ HTTP แบบไม่เข้ารหัส API key และรหัสผ่านผู้ใช้ทั้งหมดจะถูกส่งผ่านเครือข่ายเป็นข้อความชัดเจน และข้อมูลรับรองของ Studio ใช้ basic authentication ซึ่งเป็นเพียงการเข้ารหัสแบบ base64 ไม่ใช่การเข้ารหัสลับ

วาง reverse proxy ไว้ด้านหน้า ให้ reverse proxy จัดการการสิ้นสุด TLS (transport layer security) และ bind Kong กับ loopback address เพื่อไม่ให้ส่วนอื่นเข้าถึงได้ ใน docker-compose.yml การกำหนดพอร์ตจะเปลี่ยนจาก kong เป็น 127.0.0.1:8000:8000 และ proxy จะ forward ไปยังพอร์ตดังกล่าว การใช้ Traefik ด้านหน้าแอป Compose หลายรายการ อธิบายส่วนการจัดการ certificate

ให้ปิดพอร์ตที่เหลือที่ firewall ด้วย เนื่องจาก Docker เปิดเผยพอร์ตโดยเขียนกฎ iptables ของตนเอง ซึ่งการตั้งค่า ufw แบบทั่วไปจะไม่ตรวจพบ กรณีนี้อธิบายไว้ใน เหตุใดคอนเทนเนอร์ Docker จึงไม่ปฏิบัติตามกฎ ufw ของคุณ

สำรองฐานข้อมูล ไม่ใช่ไดเรกทอรี

ข้อมูล Postgres อยู่ใน bind mount ที่ ./volumes/db/data การคัดลอกไดเรกทอรีดังกล่าวขณะที่ container กำลังทำงาน จะได้สำเนาที่ไม่สมบูรณ์ เนื่องจาก Postgres บัฟเฟอร์การเขียน และไฟล์บนดิสก์จะสอดคล้องกันเฉพาะเมื่อมี checkpoint เท่านั้น การกู้คืนอาจทำงานได้ตามปกติ แต่บางครั้งจะสูญเสียธุรกรรมล่าสุดไปโดยไม่แสดงข้อผิดพลาด ซึ่งเป็นรูปแบบความล้มเหลวที่เลวร้ายที่สุดสำหรับข้อมูลสำรอง

ให้ dump แทน pg_dumpall ทำงานภายใน container และสร้าง snapshot ที่สอดคล้องกัน:

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

ตรวจสอบว่าไฟล์ไม่ว่างเปล่าก่อนเชื่อถือข้อมูลสำรอง จากนั้นส่ง dump เหล่านี้ออกจากเซิร์ฟเวอร์ตามกำหนดเวลา ซึ่งเป็นหน้าที่ของ ข้อมูลสำรองนอกเซิร์ฟเวอร์แบบเข้ารหัสด้วย restic สำรอง .env พร้อมกันด้วย การสูญเสีย JWT_SECRET จะทำให้ token ที่ออกไปแล้วทั้งหมดใช้ไม่ได้ และทำให้ secret ที่เข้ารหัสและจัดเก็บไว้ทั้งหมดไม่สามารถอ่านได้

ไฟล์ที่อัปโหลดอยู่ใน ./volumes/storage และเป็นไฟล์ทั่วไป ดังนั้นการคัดลอกตามปกติจึงใช้ได้

อัปเดตโดยไม่สูญเสียข้อมูล

Supabase จะกำหนดเวอร์ชันของ image ไว้ใน docker-compose.yml ดังนั้นจะไม่มีสิ่งใดเปลี่ยนแปลงจนกว่าคุณจะสั่งให้เปลี่ยน ให้ dump ข้อมูลก่อนทุกครั้ง

docker compose pull
sh run.sh recreate

recreate จะหยุด stack แล้วเริ่มต้นใหม่อีกครั้งด้วย image ใหม่ ข้อมูลของคุณยังคงอยู่ เนื่องจากข้อมูลอยู่ใน bind mount บน host ไม่ได้อยู่ภายใน container โปรดอ่าน CHANGELOG.md ใน repository ก่อนการอัปเกรดข้าม major version เนื่องจากการอัปเกรด major version ของ Postgres ไม่ได้ดำเนินการโดยอัตโนมัติ และต้อง dump แล้ว restore

หากต้องการนำการเปลี่ยนแปลงของไฟล์ Compose มาใช้ ให้ clone upstream repository อีกครั้ง แล้วคัดลอกไดเรกทอรี docker มาทับในโปรเจกต์ของคุณ โดยระวังอย่าเขียนทับ .env

การรีเซ็ตทั้งหมด ซึ่งจะลบทุกอย่างรวมถึงฐานข้อมูล เป็นสคริปต์แยกต่างหาก และสคริปต์จะขอการยืนยัน:

sh reset.sh

FAQ

เหตุใดการเรียก API ของฉันจึงส่งคืน "Invalid authentication credentials"

ANON_KEY หรือ SERVICE_ROLE_KEY ของคุณไม่ได้ลงลายเซ็นด้วย JWT_SECRET ที่ใช้งานอยู่ใน .env เกตเวย์จะตรวจสอบลายเซ็นของทุกคำขอ และปฏิเสธเมื่อไม่ตรงกัน สร้างค่าทั้งสามรายการใหม่พร้อมกันด้วย sh utils/generate-keys.sh --update-env จากนั้นเรียกใช้ sh run.sh recreate เพื่อให้บริการอ่านค่าใหม่

สามารถใช้งาน Supabase แบบโฮสต์เองบน VPS ขนาด 2 GB ได้หรือไม่

ไม่ควรใช้งานในสภาพแวดล้อมจริงอย่างสม่ำเสมอ เนื่องจาก ณ เดือน July 2026 สแตกนี้ใช้หน่วยความจำขณะไม่มีโหลดใกล้ 3 GB เพราะทำงานประมาณ fourteen บริการ ดังนั้นเครื่องขนาด 2 GB อาจทำให้คอนเทนเนอร์ถูกยุติโดยตัวจัดการ out of memory และคุณจะเห็น exit code 137 ใน docker compose ps ใช้ 8 GB สำหรับ production และถือว่า 4 GB เป็นขนาดขั้นต่ำสำหรับการพัฒนาเพียงคนเดียว

Supabase แบบโฮสต์เองมี edge functions หรือไม่

มี ไฟล์ Compose มี runtime ของฟังก์ชันที่ใช้ Deno และให้บริการทุกอย่างที่คุณวางไว้ใต้ ./volumes/functions อย่างไรก็ตาม ไฟล์นี้ไม่มีเครือข่ายการ deploy ระดับโลกของแพลตฟอร์มแบบโฮสต์ ดังนั้นฟังก์ชันของคุณจะทำงานบนเซิร์ฟเวอร์เพียงเครื่องเดียวและในตำแหน่งเดียว

จะเชื่อมต่อฐานข้อมูล Postgres โดยตรงได้อย่างไร

ใช้ docker exec -it supabase-db psql -U postgres เพื่อเปิด interactive shell บนตัวเซิร์ฟเวอร์โดยตรง หากใช้ไคลเอนต์ภายนอก ให้เชื่อมต่อผ่าน Supavisor ที่ port 5432 ด้วยผู้ใช้ postgres.<POOLER_TENANT_ID> และ POSTGRES_PASSWORD ของคุณ อย่าเปิด port ดังกล่าวสู่อินเทอร์เน็ต ให้เข้าถึงผ่าน VPN หรือ SSH tunnel

เหตุใดอีเมลยืนยัน auth ของฉันจึงมีลิงก์ไปยัง localhost

SITE_URL และ API_EXTERNAL_URL ใน .env ยังคงเป็นค่าเริ่มต้น บริการ auth จะสร้างลิงก์ยืนยันและลิงก์รีเซ็ตรหัสผ่านทุกลิงก์จากค่าทั้งสองนี้ ดังนั้นบริการจึงส่ง address ตามที่กำหนดไว้ ตั้งค่าทั้งสองรายการเป็น URL สาธารณะจริงของคุณ แล้วสร้างสแตกใหม่