Toàn bộ hành trình từ câu hỏi đầu tiên

React + NestJS + PostgreSQL trên Hostinger: từ deploy thủ công đến nền tảng host nhiều website.

Trang này tổng hợp toàn bộ nội dung từ lúc bạn bắt đầu hỏi cách triển khai source ReactJS + NodeJS/NestJS + PostgreSQL lên Hostinger, sau đó mở rộng dần sang Docker, multi-site, CI/CD, hardening và monitoring.

Hostinger VPSUbuntu 24.04 ReactNestJSPostgreSQL NginxPM2Docker TraefikGitHub ActionsGrafana

00. Điểm bắt đầu

Bài toán ban đầu rất đơn giản: có source React + backend Node/NestJS + PostgreSQL và muốn đưa toàn bộ lên Hostinger với chi phí hợp lý.

Frontend
ReactJS

Build thành static files và serve qua Nginx.

Backend
NestJS

Chạy Node.js, API nội bộ qua port 3000.

Database
PostgreSQL

Chỉ expose nội bộ, không mở 5432 ra Internet.

InternetDomain
↓
Hostinger VPSUbuntu 24.04
↓
NginxReact + reverse proxy
NestJSlocalhost:3000
PostgreSQLlocalhost:5432

01. Chọn gói Hostinger

Ngay từ đầu, kết luận quan trọng là: nếu cần PostgreSQL cùng nằm trên Hostinger thì VPS phù hợp hơn shared hosting hoặc managed Node hosting.

Gói CPU RAM NVMe Phù hợp
KVM 1 1 vCPU 4 GB 50 GB Học, staging, app nhỏ
KVM 2 2 vCPU 8 GB 100 GB Khuyên dùng ban đầu production nhỏ/vừa
KVM 4 4 vCPU 16 GB 200 GB Nhiều website nhỏ/vừa
KVM 8 8 vCPU 32 GB 400 GB Workload lớn hơn

Tại sao không shared hosting?

Shared/managed hosting đơn giản hơn nhưng không phù hợp nếu bạn cần tự quản PostgreSQL, Node runtime, reverse proxy và các service hệ thống.

Tại sao VPS?

Full root access, tự cài PostgreSQL, Docker, Nginx/Traefik, CI/CD agentless qua SSH, và có thể host nhiều site chung một máy.

Giá khuyến mãi Hostinger thay đổi theo thời điểm và kỳ thanh toán. Website này giữ nguyên logic chọn gói, nhưng khi mua nên kiểm tra lại bảng giá hiện tại.

02. Cách deploy thủ công ban đầu

Đây là cách dễ học nhất trước khi sang Docker: cài trực tiếp Nginx, Node, PM2 và PostgreSQL lên Ubuntu.

Khởi tạo VPSUbuntu 24.04 LTS, SSH vào server bằng root/Web Console.
Cài package nềnNginx, Git, curl, build-essential, PostgreSQL.
Cài Node.jsDùng NVM và chọn đúng Node version project đang dùng.
Tạo PostgreSQL DB/userDatabase chỉ listen nội bộ; backend dùng 127.0.0.1:5432.
Deploy NestJS`npm ci`, `npm run build`, chạy `dist/main.js` bằng PM2.
Deploy React`npm run build`, Nginx serve thư mục `dist/`.
Reverse proxy + HTTPSNginx public 80/443, proxy API tới localhost:3000, Certbot tạo SSL.
Lệnh cài package cơ bản
apt update
apt upgrade -y

apt install -y \
  nginx \
  git \
  curl \
  build-essential \
  postgresql \
  postgresql-contrib
Tạo PostgreSQL database
sudo -u postgres psql

CREATE USER myapp_user WITH PASSWORD 'STRONG_PASSWORD';
CREATE DATABASE myapp_db OWNER myapp_user;
GRANT ALL PRIVILEGES ON DATABASE myapp_db TO myapp_user;
\q
NestJS + PM2
cd /var/www/myapp/backend
npm ci
npm run build

npm install -g pm2
pm2 start dist/main.js --name myapp-api
pm2 save
pm2 startup
Nginx cho React + API
server {
    listen 80;
    server_name example.com www.example.com;

    root /var/www/myapp/frontend/dist;
    index index.html;

    location / {
        try_files $uri $uri/ /index.html;
    }
}

server {
    listen 80;
    server_name api.example.com;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Ưu điểm

Dễ hiểu luồng server, ít abstraction, phù hợp khi mới học VPS/Linux/Nginx.

Nhược điểm

Khó nhân bản, khó rollback, dependency dễ rối, nhiều site sẽ khó quản lý nếu tiếp tục cài trực tiếp.

03. Nâng cấp sang Docker

Sau khi hiểu deploy thủ công, bước tiếp theo là đóng gói từng thành phần để deploy nhất quán và dễ rollback hơn.

React build→Nginx container→ /api →NestJS container→PostgreSQL container

Frontend

Multi-stage Dockerfile: Node build → Nginx runtime.

Backend

NestJS listen `0.0.0.0:3000`; không cần PM2 khi Docker có restart policy.

Database

Postgres volume riêng; không publish 5432 ra host.

NestJS phải listen trên 0.0.0.0
await app.listen(
  process.env.PORT ?? 3000,
  '0.0.0.0',
);
Database URL trong Docker
DATABASE_URL=postgresql://myapp_user:PASSWORD@db:5432/myapp_db

Trong Compose, `db` là hostname service. Không dùng `localhost` từ backend container.

Frontend dùng cùng domain
VITE_API_URL=/api

Frontend gọi `/api/...`, Nginx container proxy request vào service `backend:3000`.

Từ giai đoạn này, architecture tốt hơn là frontend + API cùng domain, ví dụ `example.com` và `example.com/api`, giúp giảm CORS/DNS/SSL complexity.

04. Host nhiều website trên cùng VPS

Khi bắt đầu có nhiều project tương tự, không nên gán tay 8081/8082/8083 cho từng site. Dùng một Traefik gateway chung và mỗi site là một Compose project riêng.

InternetNhiều domain
↓
Traefik80/443 · TLS · Host routing
↓
site-a.comFrontend A → Backend A → DB A
site-b.comFrontend B → Backend B → DB B
site-c.comFrontend C → Backend C → DB C
/opt/
├── infrastructure/
│   ├── traefik/
│   └── monitoring/
├── sites/
│   ├── site-a/
│   ├── site-b/
│   └── site-c/
└── backups/
    ├── site-a/
    ├── site-b/
    └── site-c/

DB riêng từng site

Dễ cô lập lỗi, backup/restore và xóa site. Phù hợp giai đoạn 2–5 site hoặc khi isolation quan trọng.

Shared PostgreSQL

Tiết kiệm RAM khi site tăng nhiều, nhưng tăng blast radius nếu PostgreSQL chung gặp sự cố.

Frontend của mỗi site nối vào cả `internal` và `traefik-proxy`; backend và DB chỉ ở `internal`. Traefik là thành phần duy nhất publish 80/443.

05. CI/CD: từ build trên VPS đến build trên GitHub

Khi số site tăng, build trực tiếp trên VPS dễ gây CPU/RAM spike. Kiến trúc tốt hơn là GitHub Actions build image và đẩy lên GHCR.

git push→GitHub Actions→Build images→GHCR→SSH VPS→docker compose pull/up

Frontend image

`ghcr.io/org/site-frontend:<git-sha>`

Backend image

`ghcr.io/org/site-backend:<git-sha>`

APP_VERSION

Production giữ exact Git SHA để rollback rõ ràng.

Deploy flow tốt hơn
git push origin main

# GitHub Actions
1. docker build frontend
2. docker build backend
3. push images to GHCR
4. SSH into VPS
5. backup database
6. run migration hook
7. docker compose pull
8. docker compose up -d
9. health check

Không nên dựa hoàn toàn vào tag `latest` cho production. Dùng Git SHA giúp xác định chính xác version đang chạy và rollback dễ hơn.

06. Backup, migration và rollback

App rollback khá dễ; database rollback thì không. Vì vậy backup/migration phải được xem là một phần của deployment.

Backup DB→Migration→Deploy app→Health check
Backup PostgreSQL
docker compose exec -T db \
  pg_dump \
    -U "$POSTGRES_USER" \
    "$POSTGRES_DB" \
  | gzip \
  > /opt/backups/site-a/pre-deploy-$(date +%Y%m%d-%H%M%S).sql.gz
Prisma migration
docker compose run --rm backend \
  npx prisma migrate deploy
TypeORM migration
docker compose run --rm backend \
  npm run migration:run

Rollback app

Đổi `APP_VERSION` về Git SHA cũ rồi pull/up lại container.

Rollback DB

Không tự động mù quáng. Schema có thể đã thay đổi theo cách không backward-compatible.

Migration production an toàn hơn theo pattern: Add → Migrate → Switch → Remove later.

07. Hardening VPS

Security phải làm theo thứ tự để tránh tự khóa SSH.

Tạo `deploy` userThêm SSH public key.
Test SSH bằng terminal mớiChỉ tiếp tục nếu login key thành công.
Tắt root/password SSH`PermitRootLogin no`, `PasswordAuthentication no`.
Hostinger Firewall + UFWPublic: 22, 80, 443.
Fail2ban + unattended upgradesGiảm brute-force và tự cập nhật security fixes.
Audit Docker exposureBackend/DB không được publish port ra host.
docker ps --format 'table {{.Names}}\t{{.Ports}}'
sudo ss -lntup
sudo ufw status verbose
sudo fail2ban-client status sshd

User thuộc `docker` group có quyền rất cao trên host. Không thêm developer/customer thông thường vào group này.

08. Monitoring: biết sự cố trước người dùng

Sau khi hạ tầng ổn, bước tiếp theo là quan sát CPU/RAM/Disk, container usage, HTTP uptime, API health và SSL expiry.

Node Exporter

CPU, RAM, disk, load, network của VPS.

cAdvisor

CPU/RAM/network theo container.

Blackbox Exporter

Website/API uptime, latency và TLS expiry.

Prometheus

Lưu metrics và evaluate alert rules.

Grafana + Alertmanager

Dashboard và lớp alert routing.

Alert Ngưỡng gợi ý Mục đích
WebsiteDown Fail > 2 phút Site/API không truy cập được
HighCPU > 85% trong 10 phút Server có nguy cơ quá tải
HighMemory > 90% trong 10 phút Nguy cơ OOM
LowDisk < 15% free Images/logs/DB/backups đầy disk
SSLExpiring < 14 ngày ACME renewal có thể lỗi

09. Vận hành hàng ngày

Cheat sheet các lệnh quan trọng sau khi hệ thống đi vào production.

Docker
docker compose ps
docker compose logs -f backend
docker compose logs -f db
docker stats
docker system df
docker compose pull
docker compose up -d
VPS resources
free -h
df -h
htop
sudo ss -lntup
Không nên chạy tùy tiện
docker compose down -v
docker system prune --volumes

Các lệnh này có thể xóa volume/dữ liệu nếu bạn không hiểu chính xác hậu quả.

10. Lộ trình nâng cấp theo quy mô

Không cần nhảy ngay lên Kubernetes. Mở rộng dần theo nhu cầu và metrics thực tế.

Giai đoạn 11 VPS, Nginx/PM2/Postgres thủ công để hiểu nền tảng.
Giai đoạn 2Docker Compose cho 1 app.
Giai đoạn 3Traefik + nhiều Compose project.
Giai đoạn 4GitHub Actions + GHCR + exact Git SHA deploy.
Giai đoạn 5Hardening + monitoring + off-site backup.
Giai đoạn 6Tách DB / tách business-critical app sang VPS riêng nếu cần.
Shared VPSSite A · B · C · D
↓ khi một app quan trọng hơn
Shared VPSApp thường
Dedicated VPSBusiness-critical app
DB VPSNếu cần tách data tier

11. Checklist từ đầu đến production

Tick trực tiếp; trạng thái được lưu trên trình duyệt.

12. Setup Guides & Downloads

Mỗi bộ setup giờ có trang chi tiết riêng với kiến trúc, prerequisites, step-by-step, verification và troubleshooting.

Single-site

React + NestJS + PostgreSQL Docker

Deploy một website hoàn chỉnh bằng Docker Compose.

Multi-site

Hostinger Multi-site Platform

Traefik + nhiều Docker Compose project + GHCR.

Security

VPS Hardening Add-on

SSH key-only, UFW, Fail2ban và security audit.

Observability

Monitoring Add-on

Prometheus, Grafana, cAdvisor, Blackbox và Alertmanager.