Seminar Docs / Cloud

DEPLOYMENT
STACK

Toàn bộ hệ thống chạy trên một DigitalOcean Droplet tại Singapore, được orchestrate bởi Coolify và Docker. Zero third-party PaaS phí.

Network Flow

InternetUser browser
TraefikReverse Proxy + SSL
Next.jsFrontend :3000
ExpressBackend :5123
MongoDBDatabase :27017 (internal)

Latency to VN

< 15ms

SGP1 → HCM

SSL

Auto

Let's Encrypt

Deploy time

~90s

Git push to live

Containers

2

Frontend + Backend

Tech Stack — Chi tiết từng thành phần
Infrastructure
🌊

DigitalOcean VPS

Droplet — Singapore SG1

Cách hoạt động

DigitalOcean Droplet đặt tại Singapore giúp giảm độ trễ về Việt Nam xuống dưới 30ms. So với server đặt ở US (~200ms) hay EU (~180ms), đây là lựa chọn tối ưu cho người dùng Đông Nam Á.

Tại sao chọn?

Latency từ HCM City đến SGP1 ≈ 8–15ms. Toàn bộ backend, frontend và database đều chạy trên cùng một Droplet, loại bỏ chi phí cross-region network.

RegionSGP1 — Singapore
OSUbuntu 24.04 LTS
vCPU2 cores
RAM2 GB
Storage50 GB SSD
Containerization
🐳

Docker

Build once, run anywhere

Cách hoạt động

Mỗi service (Next.js frontend, Express backend) được đóng gói vào một Docker container riêng. Container share cùng Docker network "coolify" để communicate nội bộ mà không cần expose port ra internet.

Tại sao chọn?

Không còn "works on my machine" — container trên máy dev sẽ chạy y hệt trên VPS. Rollback dễ dàng bằng cách pull image cũ. Scaling bằng cách tăng replica.

EngineDocker 26.x
Networkcoolify — bridge
BackendNixpacks image
FrontendNixpacks image
IsolationPer-service containers
PaaS / CI-CD
🚀

Coolify

Self-hosted Heroku alternative

Cách hoạt động

Coolify là một PaaS tự host trên VPS của chính mình — không phụ thuộc vào Vercel hay Heroku. Kết nối GitHub repo, mỗi lần push code là Coolify tự động build Docker image và deploy lên server.

Tại sao chọn?

Traefik (reverse proxy tích hợp sẵn) tự động cấp SSL từ Let's Encrypt và route traffic đến đúng container. Zero-downtime deploy nhờ health check trước khi switch traffic.

Versionv4.0 beta
BuildNixpacks (auto-detect)
ProxyTraefik v2
SSLLet's Encrypt auto
DeployGit push → auto build
Database
🍃

MongoDB (Coolify)

Self-hosted on VPS — same Droplet

Cách hoạt động

MongoDB chạy như một container được Coolify quản lý trực tiếp trên cùng Droplet với backend. Coolify cung cấp giao diện để tạo database, set credentials, và tự động inject connection string vào backend container qua environment variable.

Tại sao chọn?

Vì cùng Docker network, backend Express kết nối đến MongoDB qua internal hostname — không qua internet, không tốn băng thông, latency dưới 1ms. Không phụ thuộc Atlas hay dịch vụ bên ngoài. Toàn bộ stack nằm trên một VPS duy nhất.

TypeNoSQL Document DB
HostCoolify managed container
NetworkInternal Docker bridge
ODMMongoose v8
Latency< 1ms (same host)
CDN / Storage
🗂️

DigitalOcean Spaces

S3-compatible Object Storage

Cách hoạt động

Cover images của bài viết được upload lên DigitalOcean Spaces thay vì lưu trực tiếp trên VPS. File được serve qua CDN edge nodes toàn cầu — user ở Hà Nội tải ảnh từ node gần nhất thay vì VPS Singapore.

Tại sao chọn?

Dùng AWS SDK (@aws-sdk/client-s3) vì Spaces tương thích 100% S3 API. Upload flow: Browser → Next.js proxy API → Express → Spaces. Giấu S3 credentials hoàn toàn, không expose ra client.

ProtocolS3-compatible API
RegionSGP1 — Singapore
CDNEnabled (edge cache)
SDK@aws-sdk/client-s3
ACLpublic-read per object
CI/CD Pipeline — Từ code đến production
01

Git Push

Developer push code lên GitHub repo (main branch)

02

Webhook Trigger

GitHub gửi webhook đến Coolify trên VPS

03

Nixpacks Build

Coolify chạy Nixpacks để detect và build Docker image từ source code

04

Health Check

Container mới khởi động, Coolify kiểm tra /health endpoint

05

Traffic Switch

Traefik chuyển toàn bộ traffic sang container mới. Container cũ bị stop.

06

SSL Auto-renew

Let's Encrypt tự gia hạn cert 30 ngày trước khi expire

Internal Networking — Frontend ↔ Backend

❌ Cách sai (localhost)

# Frontend gọi backend bằng:
http://localhost:5123/api/posts
# ❌ localhost trong container = chính nó, không phải backend container

Khi frontend container gọi localhost, nó resolve đến chính container đó — không phải backend container. Request sẽ fail với ECONNREFUSED.

✓ Cách đúng (Docker network alias)

# Env var trên frontend container:
INTERNAL_BACKEND_URL=http://seminar-backend:5123
# ✓ Docker DNS resolve "seminar-backend" → backend container IP

Cả hai container cùng join Docker network coolify. Docker's internal DNS tự động resolve container alias seminar-backend thành IP của backend container. Traffic không ra internet.

Environment Variables — Coolify Config

ServiceVariableValue
FrontendINTERNAL_BACKEND_URLhttp://seminar-backend:5123
FrontendNEXTJS_REVALIDATE_TOKEN(shared secret)
BackendNEXTJS_URLhttps://ie213saigonblog.online
BackendMONGODB_URImongodb://user:pass@mongo:27017/db
BackendSPACES_ENDPOINThttps://sgp1.digitaloceanspaces.com
Tại sao không dùng Vercel / Railway?

Chi phí

  • Vercel Pro: $20/tháng/người
  • Railway Starter: $5/tháng + usage
  • DigitalOcean Droplet 2GB: $18/tháng
  • Coolify + MongoDB: Free & self-hosted
  • Toàn bộ stack trên 1 Droplet duy nhất

Kiểm soát

  • Vercel lock-in Next.js Edge Runtime
  • Không thể chạy custom TCP server
  • Coolify: full root access VPS
  • Tự cấu hình Traefik headers
  • Không bị giới hạn bởi platform rules

Học thuật

  • Hiểu rõ Docker networking từ đầu
  • Debug thực tế: container DNS, SSL, proxy
  • CI/CD pipeline từ GitHub VPS
  • Không bị abstraction layer che khuất
  • Real DevOps experience