Deploy NodeJS bằng Docker trên VPS Ubuntu: quy trình chuẩn cho production
Deploy app NodeJS lên VPS nghe đơn giản: copy code, npm install, node server.js. Nhưng production khác hẳn. Chỉ cần 1 lần restart lỗi, 1 lần thiếu biến môi trường, 1 lần memory leak không bị giới hạn → downtime, log rối, rollback khó. Docker giải bài toán này khá gọn: môi trường chạy đồng nhất, build một lần, chạy nhiều nơi, dễ kiểm soát version, scale, rollback.
Nếu bạn đang dùng VPS Ubuntu để chạy API, web backend, cron worker hoặc app fullstack NodeJS, quy trình chuẩn nên xoay quanh 4 mục tiêu: ổn định, tái lập, an toàn, dễ vận hành. Bài viết này đi từ cấu trúc production thực tế: chuẩn bị VPS, viết Dockerfile tối ưu, dùng Docker Compose, reverse proxy bằng Nginx, SSL, logging, healthcheck, deploy/rollback.
Vì sao nên deploy NodeJS bằng Docker trên VPS?
NodeJS vốn phụ thuộc mạnh vào môi trường chạy: version Node, package native, biến môi trường, file build, process manager. Docker đóng gói toàn bộ phần đó thành image.
Lợi ích chính:
– Đồng nhất môi trường: local, staging, production gần như giống nhau.
– Deploy nhanh: build image → chạy container mới.
– Rollback dễ: quay lại image/tag cũ.
– Cô lập tài nguyên: app lỗi ít kéo theo toàn server.
– Dễ chuẩn hóa: app nào cũng theo cùng 1 flow.
Tuy nhiên, production không chỉ là “dockerize” app. Chuẩn hơn phải có:
– user deploy riêng
– firewall
– reverse proxy
– HTTPS
– volume/log hợp lý
– restart policy
– healthcheck
– secret/env tách biệt
– chiến lược cập nhật
Kiến trúc tối thiểu chuẩn production
Mô hình phổ biến:
– VPS Ubuntu
– Docker Engine + Docker Compose
– Container NodeJS app
– Nginx container hoặc Nginx host làm reverse proxy
– SSL từ Let’s Encrypt
– .env cho config
– Volume cho log/file cần lưu
– CI/CD hoặc deploy script để tự động hóa
Luồng request:
– Client → Nginx :80/:443
– Nginx → NodeJS container :3000
– Container restart tự động nếu app crash
Nếu app có DB, thường tách riêng:
– DB managed service → tốt nhất cho production
– Hoặc DB chạy container riêng → chấp nhận được với hệ nhỏ, nhưng backup phải rõ ràng
Bước 1: Chuẩn bị VPS Ubuntu đúng cách
Đừng bắt đầu bằng việc cài Docker ngay. Cần harden tối thiểu.
Việc nên làm đầu tiên
– Tạo user deploy, tránh dùng root hằng ngày
– Bật SSH key auth
– Tắt password login nếu có thể
– Cấu hình timezone
– Cập nhật package
– Bật firewall
Ví dụ:
sudo apt update && sudo apt upgrade -y
sudo apt install -y ufw curl git
sudo ufw allow OpenSSH
sudo ufw allow 80
sudo ufw allow 443
sudo ufw enableNếu VPS chỉ phục vụ web:
– mở 22, 80, 443
– không mở port app nội bộ như 3000
Điểm quan trọng: container app không nên public trực tiếp ra Internet. Chỉ reverse proxy mới public.
Bước 2: Cài Docker, Compose
Trên Ubuntu, nên cài Docker từ repo chính thức để có version mới, ổn định hơn.
Sau khi cài:
– kiểm tra docker --version
– thêm user hiện tại vào group docker
– restart session
Lưu ý production:
– bật Docker daemon khi boot
– dọn image/container cũ định kỳ
– không build rác liên tục trên VPS nhỏ
Bước 3: Viết Dockerfile đúng chuẩn production
Sai lầm phổ biến:
– dùng image quá nặng
– copy toàn bộ source thiếu .dockerignore
– chạy bằng root
– nhét cả dev dependency vào production image
Một Dockerfile tốt nên có các đặc điểm:
– base image rõ version, ví dụ node:20-alpine
– cài dependency trước để tận dụng cache
– chỉ copy file cần thiết
– build app nếu dùng TypeScript/NestJS/Next custom server
– chạy user không phải root
– expose đúng port nội bộ
Ví dụ cơ bản:
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:20-alpine
WORKDIR /app
ENV NODE_ENV=production
COPY package*.json ./
RUN npm ci --omit=dev
COPY --from=builder /app/dist ./dist
USER node
EXPOSE 3000
CMD ["node", "dist/main.js"]