Cách Deploy NodeJS Bằng Docker Compose Trên VPS Từng Bước

07/05/2026 · P T P · Chung

Deploy NodeJS bằng Docker Compose trên VPS: hướng dẫn thực chiến từng bước

Deploy app NodeJS lên VPS nghe đơn giản: build app, chạy process, mở port. Thực tế hơn nhiều: env, network, persist data, restart policy, reverse proxy, SSL, log, zero-downtime tương đối. Làm thiếu 1 mắt xích → app chạy local ngon, lên server lỗi ngay.

Bài này đi theo hướng thực chiến: từ một app NodeJS bất kỳ, đóng gói bằng Docker, orchestration bằng Docker Compose, đưa lên VPS, chạy sau Nginx reverse proxy. Mục tiêu: dễ lặp lại, dễ bảo trì, ít lỗi môi trường.


Vì sao nên dùng Docker Compose trên VPS?

Nếu deploy NodeJS “thủ công”, flow thường là:

– cài Node
– pull code
npm install
– chạy pm2 hoặc node server.js
– cấu hình Nginx riêng
– cập nhật bản mới → dễ lệch môi trường

Docker Compose giải quyết khá gọn:

Đồng nhất môi trường → local/server giống nhau
Tách service rõ ràng → app, db, redis, nginx
Khởi động lại dễdocker compose up -d
Rollback dễ hơn → quay lại image/cấu hình cũ
Onboarding nhanh → dev khác chỉ cần Docker

Compose đặc biệt hợp cho:
– app nhỏ-vừa
– 1 VPS
– chưa cần Kubernetes
– muốn quy trình triển khai rõ, ít overhead


Kiến trúc triển khai đề xuất

Một mô hình phổ biến:

NodeJS app → chạy trong container
Nginx → reverse proxy, nhận request từ internet
Docker network → app/nginx nói chuyện nội bộ
VPS → Ubuntu 22.04 hoặc tương đương
Domain → trỏ về IP VPS
SSL → cấu hình sau khi app chạy ổn

Luồng request:

– User → domain
– domain → VPS
– Nginx container → forward sang Node app container
– Node app → trả response

Nếu có DB như PostgreSQL/MySQL, có 2 hướng:

– DB nằm ngoài VPS/container → ổn hơn cho production
– DB chạy cùng Compose → tiện, nhanh, nhưng cần backup kỹ


Bước 1: Chuẩn bị VPS

Trên VPS mới, cập nhật hệ thống trước:

sudo apt update && sudo apt upgrade -y

Cài Docker:

curl -fsSL https://get.docker.com | sh

Cho user hiện tại dùng Docker không cần sudo:

sudo usermod -aG docker $USER
newgrp docker

Kiểm tra:

docker --version
docker compose version

Mở firewall cơ bản:

sudo ufw allow OpenSSH
sudo ufw allow 80
sudo ufw allow 443
sudo ufw enable

Lưu ý thực tế: đừng mở port app Node trực tiếp ra internet nếu đã dùng Nginx. Chỉ cần 80/443. App nên chạy trong network nội bộ.


Bước 2: Chuẩn bị ứng dụng NodeJS

Giả sử app có cấu trúc:

app/
├── src/
├── package.json
├── package-lock.json
└── server.js

App cần lắng nghe trên 0.0.0.0, không phải localhost. Ví dụ:

app.listen(process.env.PORT || 3000, '0.0.0.0', () => {
  console.log('Server running');
});

Nếu bind localhost → container ngoài không truy cập được.

Tạo file .env:

PORT=3000
NODE_ENV=production

Không hard-code secret trong code. Dùng env.


Bước 3: Viết Dockerfile tối ưu cho production

Tạo Dockerfile:

FROM node:20-alpine

WORKDIR /app

COPY package*.json ./ RUN npm ci --omit=dev

COPY . .

EXPOSE 3000

CMD ["node", "server.js"]

Ý nghĩa:

node:20-alpine → image nhẹ
WORKDIR /app → thư mục làm việc
– copy package*.json trước → tận dụng cache layer
npm ci --omit=dev → cài đúng lockfile, bỏ devDependencies
EXPOSE 3000 → mô tả cổng app dùng
CMD → lệnh chạy chính

Tạo thêm .dockerignore:

node_modules
npm-debug.log
.git
.env
Dockerfile
docker-compose.yml

.dockerignore tốt → build nhanh hơn, image sạch hơn.


Bước 4: Tạo Docker Compose

Tạo docker-compose.yml:

version: '3.9'

services: app: build: . container_name: node_app restart: always env_file: - .env expose: - "3000" networks: - app_network

nginx: image: nginx:alpine container_name: nginx_proxy restart: always ports: - "80:80" volumes: - ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro depends_on: - app networks: - app_network

networks: app_network: driver: bridge

Điểm quan trọng:

restart: always → VPS reboot, container tự lên
expose thay vì ports cho app → app không public trực tiếp
– Nginx mới là service public cổng 80
– 2 container chung app_network → gọi nhau qua service name


Bước 5: Cấu hình Nginx reverse proxy

Tạo file nginx/default.conf:

server {
    listen 80;
    server_name your-domain.com www.your-domain.com;

location / { proxy_pass http://app:3000; proxy_http_version 1.1;

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; } }

Ở đây:

proxy_pass http://app:3000;app là tên service trong Compose
– header forward chuẩn → app biết IP thật, protocol thật

Nếu app có upload/file lớn, thêm:

client_max_body_size 20M;

Bước 6: Upload code lên VPS

Có nhiều cách:

git clone
scp
– CI/CD push trực tiếp

Cách đơn giản:

git clone <repo-url>
cd <project-folder>

Kiểm tra lại file:

Dockerfile
docker-compose.yml
.env
nginx/default.conf

Rồi build + chạy:

docker compose up -d --build

Kiểm tra container:

docker ps

Xem log:

docker compose logs -f

Nếu lỗi, log thường chỉ đúng chỗ: app crash, thiếu env, sai port, Nginx sai upstream.


Bước 7: Trỏ domain về VPS

Trong DNS provider, tạo:

A recordyour-domain.com → IP VPS
A recordwww.your-domain.com → IP VPS

Chờ DNS propagate vài phút đến vài giờ.

Test:

ping your-domain.com

Hoặc mở trình duyệt:
http://your-domain.com

Nếu thấy app → phần deploy cơ bản đã xong.


Bước 8: Thêm SSL cho production

Chạy HTTP thôi chưa đủ. Production nên có HTTPS.

Có 2 hướng:

– Certbot trên host
– Nginx Proxy Manager / Traefik / Caddy

Với mô hình đơn giản, có thể cài Certbot ngay trên VPS host rồi mount cert vào Nginx. Tuy nhiên cách này cần thêm cấu hình. Nếu muốn tối giản hơn, nhiều team chọn Caddy hoặc Traefik vì tự cấp SSL.

Nếu vẫn dùng Nginx thuần, sau khi có cert, config sẽ có:

– server 80 → redirect 443
– server 443 → dùng ssl_certificate, ssl_certificate_key

Điểm mấu chốt: đừng xem SSL là bước “để sau rất lâu”. App public không có HTTPS → kém an toàn, browser cảnh báo.


Bước 9: Cập nhật phiên bản mới

Khi có code mới:

git pull
docker compose up -d --build

Flow này đủ cho đa số app nhỏ-vừa.

Nếu muốn dọn image cũ:

docker image prune -a

Cảnh báo bảo mật và dữ liệu: lệnh trên sẽ xóa image không còn được container sử dụng. Nếu bạn đang giữ image cũ để rollback, đừng chạy vội.

Nếu cần restart nhanh:

docker compose restart

Nếu muốn dừng toàn bộ:

docker compose down

Các lỗi thực tế rất hay gặp

App chạy local, lên VPS lỗi 502

Thường do:

– app không listen 0.0.0.0
– sai port
– container app crash
– Nginx proxy nhầm host/port

Check:

docker compose logs app
docker compose logs nginx

Env không load

Nguyên nhân:

– file .env thiếu biến
– sai tên biến
– app đọc env trước khi config đúng

Fix:
– kiểm tra env_file
– log thử process.env.PORT

Build chậm, image nặng

Nguyên nhân:
– copy cả node_modules
– không có .dockerignore
– dùng image base quá lớn

Fix:
– thêm .dockerignore
– dùng node:alpine
– tối ưu layer build

Mất dữ liệu khi redeploy

Nếu có DB trong container mà không mount volume → down/recreate dễ mất data.

Fix:
– dùng named volume
– hoặc tách DB sang managed service


Một số mẹo production đáng giá

Dùng healthcheck → Compose biết container còn khỏe không
Giới hạn log → tránh đầy disk
Backup định kỳ → nhất là DB, uploads
Không chạy app bằng root nếu có thể
Tách .env production khỏi code repo
Dùng tag image cố định thay vì latest trong môi trường quan trọng
Giám sát CPU/RAM/disk → VPS nhỏ rất dễ đầy ổ vì log/image

Compose không phải “chuẩn cuối cùng”, nhưng với 1 VPS, nó là điểm cân bằng rất tốt giữa đơn giảnđủ chuyên nghiệp.


Kết luận

Deploy NodeJS bằng Docker Compose trên VPS là một lựa chọn cực thực dụng: nhanh setup, dễ lặp lại, ít lệch môi trường, phù hợp production quy mô nhỏ-vừa. Quy trình cốt lõi chỉ gồm vài khối:

– đóng gói app bằng Dockerfile
– ghép service bằng docker-compose.yml
– đặt Nginx làm reverse proxy
– trỏ domain, thêm SSL
– dùng log + restart policy để vận hành ổn định

Điều quan trọng nhất không phải “chạy được”, mà là chạy ổn định sau nhiều lần cập nhật. Khi bạn có thể git pulldocker compose up -d --build và hệ thống vẫn lên mượt, lúc đó quy trình deploy mới thật sự trưởng thành.

Nếu mới bắt đầu, hãy triển khai trước với 1 app NodeJS + 1 Nginx container. Khi quen rồi, bạn có thể mở rộng thêm PostgreSQL, Redis, CI/CD, auto SSL, monitoring. Đi từng bước như vậy → ít lỗi, dễ kiểm soát, sát thực tế hơn nhiều.

#bang #compose #deploy #docker #nodejs
Chia sẻ:
← Trước
Deploy NodeJS API lên VPS với Docker và Nginx Chuẩn Nhanh Gọn

Bài viết tương tự

Bình luận

Chưa có bình luận. Hãy là người đầu tiên!