Tự xây backend thay thế Supabase với PostgreSQL, Auth và Storage mã nguồn mở
Supabase hấp dẫn vì giải quyết nhanh 3 bài toán cốt lõi: database, authentication, storage. Tạo project, có PostgreSQL, API realtime, auth email/password, OAuth, bucket upload file — mọi thứ gần như dùng ngay. Nhưng khi sản phẩm lớn dần, câu hỏi xuất hiện: có nên tự xây backend tương tự Supabase bằng mã nguồn mở không?
Câu trả lời: có, nếu bạn cần kiểm soát sâu hơn về chi phí, bảo mật, dữ liệu, hạ tầng, tuỳ biến nghiệp vụ. Không, nếu team nhỏ cần ship nhanh, ít DevOps, chưa có nhu cầu đặc biệt.
Bài viết này đi vào kiến trúc thực tế: dùng PostgreSQL, Auth mã nguồn mở, Object Storage tương thích S3, API layer, migration, phân quyền, triển khai. Mục tiêu: xây backend “kiểu Supabase”, nhưng tự chủ hơn.
1. Supabase thật sự gồm những gì?
Supabase không chỉ là PostgreSQL. Nó là tổ hợp nhiều thành phần:
– PostgreSQL → DB chính. – PostgREST → tự sinh REST API từ schema PostgreSQL. – GoTrue / Supabase Auth → auth, JWT, OAuth. – Realtime server → subscribe thay đổi DB. – Storage API → quản lý file/object. – Dashboard → quản trị. – Edge Functions → logic serverless. – Row Level Security (RLS) → phân quyền ở tầng DB.
Khi tự xây, không nhất thiết clone 100%. Nên bắt đầu từ lõi:
– PostgreSQL – Auth – Storage – API backend – Migration – Observability – Backup
Realtime, dashboard, edge functions → thêm sau nếu thật sự cần.
2. Kiến trúc đề xuất
Một kiến trúc tự host gọn, bền:
Client App
↓
API Gateway / Backend
↓
PostgreSQL
↓
Auth Provider
↓
S3-compatible StorageCụ thể:
– PostgreSQL: database chính. – Keycloak / Ory Kratos / Authentik / Lucia Auth: auth. – MinIO / Garage / SeaweedFS / Ceph: object storage. – Node.js/NestJS, FastAPI, Go, Laravel, Django: backend API. – Prisma / Drizzle / SQLAlchemy / Diesel: DB access. – Flyway / Liquibase / Atlas / Prisma Migrate: migration. – Caddy / Nginx / Traefik: reverse proxy + TLS. – Docker Compose / Kubernetes: deploy.
Khuyến nghị thực dụng:
– Team nhỏ → Docker Compose + PostgreSQL managed/self-host + MinIO. – Team trung bình → Kubernetes + managed PostgreSQL + S3-compatible storage. – Sản phẩm production nghiêm túc → managed PostgreSQL nếu không có DBA.
3. PostgreSQL: trung tâm của hệ thống
PostgreSQL vẫn là lựa chọn tốt nhất cho backend hiện đại:
– Quan hệ dữ liệu mạnh. – Transaction chuẩn. – Index đa dạng. – JSONB linh hoạt. – Full-text search. – Extension phong phú. – RLS hỗ trợ phân quyền sâu.
Thiết kế schema
Ví dụ cơ bản:
create table users (
id uuid primary key,
email text unique not null,
display_name text,
created_at timestamptz default now()
);
create table projects (
id uuid primary key default gen_random_uuid(),
owner_id uuid not null references users(id),
name text not null,
created_at timestamptz default now()
);
Nếu dùng external auth, bảng users trong DB thường chỉ là profile mirror, không lưu password.
Migration
Không sửa DB thủ công trên production. Luôn dùng migration:
– Dev tạo migration. – CI test migration. – Staging chạy trước. – Production chạy sau.
Tool hợp lý:
– TypeScript → Prisma Migrate, Drizzle Kit, Atlas. – Java → Flyway, Liquibase. – Python → Alembic. – Go → golang-migrate, Atlas.
Backup
Backup là phần nhiều team quên nhất.
Tối thiểu:
– Backup hằng ngày. – WAL archiving nếu cần point-in-time recovery. – Test restore định kỳ. – Backup encrypt. – Backup lưu ngoài server chính.
DB chết mà không restore được → không có backup.
4. Auth mã nguồn mở: chọn theo nhu cầu
Auth là vùng dễ tự tin sai. Login không chỉ là email/password. Cần:
– Password hashing. – Email verification. – Reset password. – Session/JWT. – OAuth. – MFA. – Device/session management. – Rate limit. – Audit log.
Các lựa chọn phổ biến
Keycloak
Phù hợp enterprise:
– OAuth2/OIDC/SAML. – Social login. – MFA. – User federation. – Admin UI mạnh. – Realm/client/role đầy đủ.
Nhược:
– Nặng. – Cấu hình phức tạp. – UX cần custom nhiều.
Ory Kratos + Hydra
Phù hợp hệ thống cần auth cực linh hoạt:
– Identity management. – Login/registration flow. – OAuth2 server qua Hydra. – Headless, API-first.
Nhược:
– Learning curve cao. – Cần tự ghép UI, flow.
Authentik
Dễ dùng hơn Keycloak trong nhiều case:
– SSO. – OAuth/OIDC/SAML. – Admin UI tốt. – Self-host thuận tiện.
Lucia Auth / Auth.js
Phù hợp app tự code backend:
– Nhẹ. – Dễ tích hợp framework. – Kiểm soát session tốt.
Nhược:
– Không phải identity platform đầy đủ. – Nhiều tính năng phải tự làm.
JWT hay session?
– App SPA/mobile → access token + refresh token. – Web app truyền thống → httpOnly cookie session. – Microservices → JWT/OIDC. – Bảo mật cao → session server-side dễ revoke hơn.
Đừng lưu token trong localStorage nếu có thể tránh. Ưu tiên httpOnly, Secure, SameSite cookie.
5. Storage: thay thế Supabase Storage
Supabase Storage thực chất là object storage + metadata + access policy. Tự xây có thể dùng:
– MinIO: phổ biến, S3-compatible, dễ self-host. – Garage: nhẹ, distributed, hợp homelab/small infra. – SeaweedFS: mạnh cho lượng file lớn. – Ceph: enterprise, phức tạp. – AWS S3 / Cloudflare R2 / Backblaze B2: managed, vẫn dùng chuẩn mở S3 API.
Kiến trúc storage nên có
Client
↓ request upload URL
Backend
↓ tạo presigned URL
Object StorageFlow tốt:
1. Client gọi backend xin upload. 2. Backend kiểm tra auth/quota/permission. 3. Backend tạo presigned URL. 4. Client upload trực tiếp lên storage. 5. Backend lưu metadata vào PostgreSQL.
Ví dụ bảng metadata:
create table files (
id uuid primary key default gen_random_uuid(),
owner_id uuid not null references users(id),
bucket text not null,
object_key text not null,
mime_type text,
size_bytes bigint,
created_at timestamptz default now()
);Ưu điểm:
– Backend không phải stream file lớn. – Dễ kiểm soát quyền. – Dễ audit. – DB biết file thuộc user/project nào.
Public/private file
– File public → dùng CDN/cache.
– File private → luôn cấp signed URL ngắn hạn.
– Không để bucket private bị public nhầm.
– Không tin client gửi owner_id.
6. API layer: không nên bỏ qua
Supabase tiện vì tự sinh API. Nhưng khi tự xây, nên có backend rõ ràng. Lý do:
– Business logic phức tạp. – Validation. – Permission. – Rate limit. – Audit. – Integration thanh toán/email/webhook. – Không expose DB schema trực tiếp.
Stack gợi ý:
– NestJS + Prisma/Drizzle → TypeScript mạnh. – FastAPI + SQLAlchemy → Python nhanh. – Go + sqlc/ent → performance, deploy nhẹ. – Django/Laravel → full-stack backend ổn định.
Pattern nên dùng:
Controller → Service → Repository/DBKhông bắt buộc quá enterprise, nhưng tách lớp giúp code sống lâu.
Validation
Luôn validate input:
– Type. – Length. – Format. – Ownership. – Business constraints.
Dùng:
– Zod / Valibot cho TypeScript. – Pydantic cho Python. – Joi / class-validator. – Request schema trong OpenAPI.
7. Phân quyền: app-level hay RLS?
Supabase nổi bật nhờ Row Level Security. Tự xây có 2 hướng.
App-level authorization
Backend kiểm tra quyền trước khi query:
where: {
id: projectId,
ownerId: currentUser.id
}Ưu:
– Dễ hiểu. – Dễ debug. – Phù hợp đa số app.
Nhược:
– Dev quên filter → leak data. – Logic phân quyền rải rác.
PostgreSQL RLS
DB tự chặn row không hợp lệ.
Ưu:
– Bảo vệ tầng sâu. – Hợp multi-tenant. – Giảm rủi ro query sai.
Nhược:
– Khó debug. – Cần quản lý DB role/session variable tốt. – ORM đôi khi gây rối.
Thực tế: bắt đầu app-level. Nếu SaaS multi-tenant lớn → cân nhắc RLS cho bảng nhạy cảm.
8. Docker Compose mẫu tối giản
Một setup local:
services:
postgres:
image: postgres:16
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: app_password
POSTGRES_DB: appdb
ports:
- "5432:5432"
volumes:
- pgdata:/var/lib/postgresql/data
minio:
image: minio/minio
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: minio
MINIO_ROOT_PASSWORD: minio_password
ports:
- "9000:9000"
- "9001:9001"
volumes:
- miniodata:/data
volumes:
pgdata:
miniodata:
Auth có thể thêm Keycloak:
keycloak:
image: quay.io/keycloak/keycloak:25.0
command: start-dev
environment:
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: admin_password
ports:
- "8080:8080"Production cần secret manager, TLS, backup, monitoring. Không dùng password mẫu.
9. Observability, bảo mật, vận hành
Backend tự xây → bạn chịu trách nhiệm vận hành.
Checklist tối thiểu:
– HTTPS bắt buộc. – Secret không commit Git. – Rate limit login/upload/API. – Audit log hành động quan trọng. – DB connection pool. – Migration có rollback plan. – Log structured JSON. – Metrics: CPU, RAM, disk, DB connections, slow queries. – Alert khi disk đầy, DB down, backup fail. – Sentry/OpenTelemetry cho lỗi app. – pg_stat_statements để xem query chậm.
Bảo mật file:
– Scan virus nếu user upload file công khai. – Giới hạn size. – Kiểm tra MIME thật, không chỉ tin header. – Random object key. – Không dùng filename gốc làm path trực tiếp.
10. Khi nào nên tự xây?
Nên tự xây nếu:
– Cần kiểm soát dữ liệu/hạ tầng. – Chi phí Supabase tăng khó dự đoán. – Cần auth/storage flow đặc thù. – Có DevOps/backend đủ mạnh. – Sản phẩm cần compliance riêng. – Muốn tránh vendor lock-in.
Không nên nếu:
– MVP cần ra nhanh. – Team không có người vận hành DB. – Chưa rõ product-market fit. – Auth/storage đơn giản. – Downtime/backup chưa ai chịu trách nhiệm.
Một chiến lược tốt: bắt đầu với Supabase hoặc managed service, sau đó tách dần. Hoặc tự xây từ đầu nhưng dùng managed PostgreSQL/S3 để giảm gánh nặng.
Kết luận thực tế
Tự xây backend thay thế Supabase hoàn toàn khả thi. Lõi kỹ thuật không quá bí ẩn: PostgreSQL cho dữ liệu, Keycloak/Ory/Authentik hoặc auth tự code cho định danh, MinIO/S3 cho storage, backend API cho nghiệp vụ.
Nhưng cái khó không nằm ở việc chạy container. Cái khó là vận hành an toàn lâu dài: migration, backup, restore, monitoring, bảo mật, phân quyền, scale, incident response.
Nếu bạn cần tốc độ → Supabase rất đáng dùng. Nếu bạn cần tự chủ, tuỳ biến sâu, kiểm soát chi phí dài hạn → backend mã nguồn mở là hướng bền vững. Cách khôn ngoan nhất: xây theo từng lớp, giữ kiến trúc đơn giản, dùng chuẩn mở như PostgreSQL, OIDC, S3. Khi đó, dù không dùng Supabase, bạn vẫn có một nền tảng backend hiện đại, linh hoạt, dễ mở rộng.
Bình luận (0)
Chưa có bình luận. Hãy là người đầu tiên!