
Trả lời nhanh: Supabase self-host chạy bằng bộ Docker Compose chính chủ: clone repo supabase/supabase, vào thư mục docker, sao chép .env.example rồi đổi hết secret mặc định (POSTGRES_PASSWORD, JWT_SECRET, ANON_KEY, SERVICE_ROLE_KEY, mật khẩu Studio), docker compose up -d: toàn bộ API vào ra qua cổng Kong 8000. VPS 4GB RAM là mức khởi điểm tử tế, NVMe cho Postgres.
Supabase được tìm 18.100 lượt/tháng ở Việt Nam, Firebase mã nguồn mở với Postgres làm ruột, và khác Firebase ở điều quan trọng nhất: tự host được toàn bộ. Blog TND đã có bài tính RAM/ổ đĩa cho Supabase; cụm bài này làm nốt phần thao tác: dựng đúng ngay từ đầu, vì lỗi phổ biến nhất của self-host Supabase không phải kỹ thuật cao siêu mà là giữ nguyên secret mặc định và phơi Studio ra internet.
- Toàn bộ stack nằm trong thư mục
dockercủa repo chính chủ, không tự chế compose - Bắt buộc trước khi up: đổi HẾT secret trong .env, ANON_KEY/SERVICE_ROLE_KEY phải sinh lại theo JWT_SECRET mới
- Mọi cửa vào đi qua Kong cổng 8000: API, Auth, Storage, Realtime, cả Studio
- Studio là quyền sinh sát database, đặt sau tailnet hoặc ít nhất đổi mật khẩu + chặn IP
- Postgres là trái tim: đặt data trên NVMe, RAM 4GB khởi điểm, 8GB cho app có người dùng
Hiểu con thú trước khi cưỡi: 10 service trong stack
Supabase không phải một app, là một bó dịch vụ ghép quanh Postgres: db (Postgres, trái tim), kong (cổng API duy nhất, cổng 8000), auth/GoTrue (đăng ký đăng nhập), rest/PostgREST (tự sinh REST API từ schema), realtime (đẩy thay đổi qua websocket), storage + imgproxy (file và ảnh), meta (quản schema cho Studio), studio (giao diện quản trị), functions (edge functions), analytics/vector (log). Hiểu sơ đồ này để sau đỡ hoảng khi docker compose ps liệt kê cả chục container, và để biết tắt bớt thứ không dùng (analytics là ứng viên đầu) trên máy chật.
Dựng từng bước: 15 phút cho bản chạy được
# tren VPS Ubuntu da co Docker (bai cai Docker cua blog):
git clone --depth 1 https://github.com/supabase/supabase
cd supabase/docker
cp .env.example .env
# keo image truoc cho nhanh:
docker compose pull
# SUA .env XONG MOI CHAY (phan duoi) roi:
docker compose up -d
docker compose ps # cho toan bo healthyVào Studio: http://IP-VPS:8000: đăng nhập bằng DASHBOARD_USERNAME/PASSWORD trong .env. Nhưng khoan mở champagne: bản vừa dựng đang chạy toàn secret mẫu công khai trên GitHub, phần kế tiếp là bắt buộc, không phải tùy chọn.
Đổi secret đúng cách: chỗ 90% người dựng làm sai
Ba lớp secret phải đổi, theo đúng thứ tự: (1) POSTGRES_PASSWORD, mật khẩu database; (2) JWT_SECRET, chuỗi ngẫu nhiên ≥32 ký tự, gốc của mọi token; (3) ANON_KEY và SERVICE_ROLE_KEY, đây là chỗ hay sai nhất: hai key này là JWT ký bằng JWT_SECRET, đổi secret mà giữ key cũ là hệ thống tự mâu thuẫn, API chết kiểu khó hiểu. Sinh cặp key khớp secret mới bằng công cụ chính chủ (trang tài liệu self-hosting của Supabase có mục Generate API Keys, dán JWT_SECRET vào là ra cặp key). Cuối cùng đổi DASHBOARD_USERNAME/PASSWORD của Studio. Đổi xong: docker compose down && docker compose up -d cho ngấm toàn bộ.
Khóa cửa: Studio và cổng 8000 không dành cho cả internet
Cổng 8000 phục vụ API cho app, thường phải công khai (qua reverse proxy + HTTPS: Caddy trỏ api.ten-mien.vn vào 8000). Nhưng Studio thì không có lý do gì phơi ra: ai vào được Studio là toàn quyền dữ liệu. Cách sạch nhất, đúng bài tủ của blog này: VPS vào tailnet, Studio chỉ mở qua IP 100.x (chặn đường public bằng ufw, giữ 8000 công khai cho API còn giao diện quản trị đi cửa riêng nội bộ). Tối thiểu nhất cũng phải: mật khẩu dashboard mạnh + giới hạn IP truy cập. Nguyên tắc quen thuộc từ series Tailscale: công cụ quản trị sống trong mạng riêng, chỉ sản phẩm mới ra phố.
Phần cứng: Postgres quyết định trải nghiệm
Cả bó service này đứng trên một chân: Postgres. Bài RAM và ổ đĩa cho Supabase đã tính chi tiết; tóm gọn cho người dựng mới: 4GB RAM chạy đủ stack cho dev/side-project, 8GB khi app có người dùng thật (Postgres cần chỗ thở cho cache), và ổ NVMe không phải trang sức, mọi truy vấn, mọi auth check, mọi realtime event đều là I/O Postgres; ổ chậm là toàn stack ì theo. Volume dữ liệu nằm ở docker/volumes/db: phần S3 của cụm bài (backup) sẽ xoay quanh đúng thư mục này.
Kiểm tra sau khi dựng, sáu lệnh
# 1. Tat ca service da chay chua docker compose ps # 2. Service nao dang khoi dong lai lien tuc (dau hieu cau hinh sai) docker compose ps | grep -i restarting # 3. Postgres nhan ket noi chua docker compose exec db pg_isready # 4. Cong dang mo ra ngoai internet: chi nen thay cong ban chu dinh mo ss -ltnp # 5. Nhat ky cua service hay hong nhat docker compose logs --tail=80 auth docker compose logs --tail=80 kong # 6. Dung luong o dia con lai, Postgres day o dia la hong nang df -h && docker system df
Bốn lỗi khiến bản dựng chết sau vài ngày
| Lỗi | Hậu quả | Cách tránh |
|---|---|---|
| Giữ nguyên khóa bí mật mẫu | Ai đọc tài liệu công khai cũng vào được dữ liệu của bạn | Sinh lại toàn bộ khóa, và sinh lại cả khóa ký lẫn khóa dịch vụ cho khớp nhau |
| Mở cổng quản trị ra internet | Bảng điều khiển không có lớp đăng nhập mạnh trước mặt | Chỉ cho truy cập qua mạng riêng, hoặc đặt sau lớp xác thực |
| Không sao lưu Postgres | Hỏng một lần là mất toàn bộ dữ liệu người dùng | Đặt tác vụ kết xuất cơ sở dữ liệu hằng ngày, chép ra nơi khác máy |
| Để ổ đĩa đầy vì nhật ký | Cơ sở dữ liệu dừng ghi, ứng dụng chết | Đặt giới hạn kích thước nhật ký cho container ngay từ đầu |
Sinh lại khóa cho đúng
Đây là chỗ nhiều người dựng làm sai: đổi mật khẩu cơ sở dữ liệu nhưng quên đổi khóa ký, hoặc đổi khóa ký mà không sinh lại các khóa dịch vụ phái sinh từ nó. Kết quả là các thành phần không nói chuyện được với nhau, hoặc tệ hơn, vẫn dùng khóa mẫu công khai.
Thứ tự đúng: sinh khóa ký mới, sinh lại các khóa dịch vụ từ khóa ký đó, đổi mật khẩu cơ sở dữ liệu, đổi mật khẩu bảng điều khiển, rồi dựng lại toàn bộ stack chứ không chỉ khởi động lại. Sau đó kiểm tra bằng đúng sáu lệnh ở trên.
Ổ đĩa quan trọng hơn số nhân xử lý
- Ổ đĩa quan trọng hơn số nhân. Cơ sở dữ liệu đọc ghi ngẫu nhiên liên tục, nên ổ NVMe tạo khác biệt lớn hơn việc thêm nhân.
- Bộ nhớ phải đủ cho toàn bộ stack chứ không chỉ cho cơ sở dữ liệu: hơn mười thành phần chạy cùng lúc, mỗi cái ăn một phần.
- Đặt vùng nhớ tạm để tránh bị dừng tiến trình đột ngột lúc cao điểm, nhưng đừng coi nó là cách thay cho việc thêm bộ nhớ thật.
Câu hỏi thường gặp
Self-host Supabase khác gì bản cloud của hãng?
Lõi giống nhau (Postgres, Auth, Storage, Realtime). Bản cloud có sẵn backup tự động, nâng cấp, CDN, và một số tính năng nền tảng; bản self-host đổi các thứ đó lấy chi phí cố định, dữ liệu tại chỗ và không giới hạn project. Vận hành backup/update là việc của bạn, có bài riêng trong cụm.
Một VPS chạy được mấy project Supabase?
Mỗi bộ compose là một project độc lập; chạy nhiều bộ trên một máy được nếu đổi cổng và đủ RAM (mỗi bộ ăn 2-3GB trở lên). Thực dụng hơn cho nhiều app nhỏ: một project, tách schema trong cùng Postgres.
Có cần domain và HTTPS ngay không?
Dev nội bộ qua tailnet thì chưa cần. Cho app thật: Caddy + domain trỏ vào Kong 8000 là chuẩn, nhớ cập nhật các biến URL công khai trong .env (SITE_URL, API_EXTERNAL_URL) cho khớp domain, không thì email xác thực và redirect auth trỏ sai chỗ.
Máy yếu tắt bớt service nào được?
analytics (logflare) và vector là ứng viên đầu, comment trong compose nếu không cần dashboard log. Functions tắt được nếu không dùng edge functions. Đừng đụng kong, auth, rest, db, đó là bộ xương.
Bài viết liên quan
- Supabase tự host: RAM và ổ đĩa cần bao nhiêu là đủ
- Docker Compose từ A đến Z: chạy cả stack một file
- Supabase Auth tự host: đăng nhập cho app của bạn
- SSO cho startup nội bộ: Authelia self-host trên VPS
- Cài Proxmox build cloud nhỏ tại nhà: tự host vs thuê VPS, khi nào đáng?
- DigitalOcean droplet 6 USD vs TND Cloud VPS 199k cho dev VN
- Chạy Claude Code headless trên VPS Ubuntu qua tmux + SSH (A-Z)
- Gemini API: lấy key miễn phí + tích hợp vào AI agent trên VPS
- Ollama là gì? Chạy AI ngay trên máy của bạn, miễn phí



