Deploy NodeJS API lên VPS bằng Docker + Nginx reverse proxy: gọn, sạch, dễ bảo trì
Deploy NodeJS API lên VPS nghe đơn giản: cài Node, git pull, chạy pm2, mở port. Làm được, nhưng dễ vỡ: lệch môi trường, restart lỗi, SSL rối, scale khó, rollback mệt. Cách ổn hơn: đóng gói app bằng Docker, để Nginx làm reverse proxy, nhận HTTPS, chuyển tiếp req vào container API.
Mô hình này phổ biến vì rõ trách nhiệm:
– Docker → chuẩn hóa môi trường chạy
– NodeJS container → chỉ lo business logic
– Nginx → public entrypoint, reverse proxy, SSL, gzip, rate limit cơ bản
– VPS → host duy nhất, chi phí thấp, đủ cho nhiều side project/sản phẩm nhỏ
Bài này hướng dẫn triển khai thực chiến: từ chuẩn bị VPS, viết Dockerfile, docker-compose.yml, cấu hình Nginx, đến vận hành/log/debug.
Kiến trúc mục tiêu
Luồng req:
– Client → Nginx :80/:443
– Nginx → proxy → NodeJS API container :3000
– Docker network nội bộ → container nói chuyện với nhau
– Chỉ Nginx expose ra Internet
Ưu điểm:
– Tách biệt tầng web/app
– Ẩn port app nội bộ
– Deploy/redeploy nhanh
– Rollback dễ
– Dễ thêm SSL bằng Let’s Encrypt
1. Chuẩn bị VPS
Tối thiểu:
– Ubuntu 22.04 hoặc 20.04
– RAM 1GB+ nếu API nhỏ
– Domain trỏ A record về IP VPS
– SSH access
– proxy_pass http://api:3000; → Nginx gọi container theo service nameapi
– Header X-Forwarded-* → app biết IP thật, protocol thật
– ACME path → phục vụ xác thực domain khi cấp SSL
Khởi động lần đầu:
docker compose up -d --build
Test:
curl http://api.yourdomain.com/health
Nếu ra JSON → reverse proxy ok.
6. Cấp HTTPS bằng Let’s Encrypt
Có nhiều cách. Thực dụng nhất trên VPS nhỏ: dùng Certbot container hoặc cài certbot host. Ví dụ cài trên host:
sudo apt install -y certbot
Dừng Nginx container tạm nếu cần chiếm port 80. Hoặc giữ cấu hình ACME qua webroot. Tạo cert:
– HTTP → tự redirect HTTPS
– SSL terminate tại Nginx
– API container không cần xử lý chứng chỉ
7. Quy trình deploy thực tế
Một flow đơn giản:
1. SSH vào VPS
2. Pull code mới
3. Rebuild image
4. Restart container
Lệnh:
git pull origin main
docker compose up -d --build
Nếu thay đổi chỉ ở code app → Compose rebuild service api. Nếu thay đổi config Nginx → container Nginx cũng reload lại.
Muốn dọn image cũ:
docker image prune -f
8. Log, debug, health check
Xem log app:
docker compose logs -f api
Xem log Nginx:
docker compose logs -f nginx
Kiểm tra container:
docker ps
Vào shell trong container:
docker exec -it my-api sh
Một số lỗi phổ biến:
– 502 Bad Gateway → app chết, sai port, Nginx không gọi được api:3000
– Connection refused → app listen localhost thay vì 0.0.0.0
– SSL không lên → DNS chưa trỏ đúng, port 80/443 bị chặn
– Env không ăn → quên env_file, quên restart container
Nên có endpoint /health để monitor nhanh.
9. Best practices để chạy lâu dài
Vài khuyến nghị đáng tiền:
– Không expose port API ra ngoài nếu đã có Nginx
– Dùng .env riêng production
– Set NODE_ENV=production
– Giới hạn log nếu app ghi quá nhiều
– Backup database riêng nếu DB cùng VPS
– Pin version image nếu cần ổn định cao
– Theo dõi tài nguyên bằng htop, docker stats
Nếu traffic tăng:
– Nginx vẫn giữ vai trò proxy
– Có thể scale nhiều API container
– Sau đó cân nhắc Kubernetes/Swarm hoặc tách DB/cache sang managed service
Kết luận
Deploy NodeJS API lên VPS bằng Docker + Nginx reverse proxy là điểm cân bằng rất tốt giữa đơn giản và chuẩn production cơ bản. Docker giải quyết bài toán “máy em chạy được”, Nginx xử lý public traffic và HTTPS, còn VPS giúp tiết kiệm chi phí cho giai đoạn đầu.
Nếu bạn đang chạy NodeJS bằng cách SSH vào server rồi node app.js, đây là lúc nâng cấp. Chỉ cần thiết lập một lần, các lần deploy sau gần như còn đúng 2 lệnh: git pull và docker compose up -d --build.
Ít rủi ro hơn. Dễ debug hơn. Dễ mở rộng hơn. Với đa số API nhỏ và vừa, vậy là quá đủ để đi đường dài.