Cách deploy NodeJS bằng Docker trên VPS từ A-Z cho người mới bắt đầu
Deploy app NodeJS lên VPS thường là bước khiến người mới ngại nhất: sợ lỗi môi trường, sợ “chạy ở máy em nhưng lên server lại hỏng”, sợ cấu hình Nginx, PM2, port, firewall. Tin tốt: Docker giải quyết gần hết mớ rắc rối đó.
Thay vì cài Node, package, service trực tiếp lên VPS, bạn đóng gói app vào container. Kết quả: môi trường dev/staging/prod gần như giống nhau, dễ deploy, dễ rollback, dễ scale hơn. Với người mới, đây là con đường ngắn nhất để đưa app NodeJS lên mạng một cách gọn gàng, ít lỗi.
Trong bài này, bạn sẽ đi từ 0 đến chạy được app thực tế trên VPS: chuẩn bị server, viết Dockerfile, docker-compose.yml, build image, chạy container, map domain, reverse proxy bằng Nginx, bật HTTPS, debug lỗi cơ bản.
Vì sao nên deploy NodeJS bằng Docker?
Cách cũ thường là:
– SSH vào VPS
– Cài NodeJS
– git clone
– npm install
– npm run build
– Chạy bằng PM2
Cách này vẫn ổn, nhưng có vài vấn đề:
– Lệ thuộc môi trường server → lệch version Node, thiếu package hệ thống. – Khó lặp lại → server mới phải cài lại từ đầu. – Khó rollback → deploy lỗi thì xử lý thủ công. – Dễ “rác” server → nhiều app, nhiều version, khó quản lý.
Docker giúp:
– App + môi trường → đóng gói cùng nhau. – Build một lần, chạy mọi nơi. – Tách biệt service → app này không ảnh hưởng app khác. – Triển khai chuẩn hóa → đặc biệt hữu ích khi làm team.
Bạn cần chuẩn bị gì?
Trước khi bắt đầu, hãy có:
– 1 VPS Linux: Ubuntu 22.04 là dễ nhất. – 1 app NodeJS: ví dụ Express/NestJS/Next backend. – 1 domain nếu muốn chạy thực tế có HTTPS. – Kiến thức cơ bản: – SSH vào server – dùng terminal – hiểu port là gì
Ví dụ app NodeJS chạy ở port 3000.
Bước 1: SSH vào VPS và cài Docker
Đầu tiên, đăng nhập VPS:
ssh root@your_vps_ipCập nhật hệ thống:
apt update && apt upgrade -yCài Docker:
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.shKiểm tra:
docker --versionCài Docker Compose plugin:
apt install docker-compose-plugin -yKiểm tra:
docker compose versionNếu muốn chạy Docker không cần root, thêm user vào group docker:
usermod -aG docker $USERSau đó đăng xuất, đăng nhập lại.
Bước 2: Chuẩn bị app NodeJS cho production
Giả sử cấu trúc app như sau:
my-app/
├─ src/
├─ package.json
├─ package-lock.json
└─ server.jsTrong package.json, nên có script:
{
"scripts": {
"start": "node server.js"
}
}Nếu app dùng biến môi trường, tạo file .env:
PORT=3000
NODE_ENV=productionBước 3: Viết Dockerfile
Tại thư mục gốc project, tạo file Dockerfile:
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
Giải thích nhanh:
– FROM node:20-alpine → dùng image Node nhẹ.
– WORKDIR /app → thư mục làm việc trong container.
– COPY package*.json ./ → copy file package trước để tận dụng cache.
– RUN npm ci --only=production → cài dependency production.
– COPY . . → copy source code.
– EXPOSE 3000 → app dùng port 3000.
– CMD ["npm", "start"] → lệnh chạy app.
Nếu app cần build, ví dụ TypeScript/NestJS, nên dùng multi-stage build. Ví dụ:
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
COPY package*.json ./
RUN npm ci --only=production
COPY --from=builder /app/dist ./dist
EXPOSE 3000
CMD ["node", "dist/main.js"]
Cách này giúp image cuối nhẹ hơn.
Bước 4: Tạo .dockerignore
File này giúp tránh copy file thừa vào image:
node_modules
npm-debug.log
.git
.gitignore
.env
Dockerfile
docker-compose.ymlKết quả: build nhanh hơn, image gọn hơn, tránh lộ dữ liệu không cần thiết.
Bước 5: Test Docker ngay trên máy local
Build image:
docker build -t my-node-app .Chạy container:
docker run -d -p 3000:3000 --name my-node-app my-node-appKiểm tra:
docker psXem log:
docker logs -f my-node-appNếu app mở được ở http://localhost:3000 thì Dockerfile ổn.
Dừng và xóa:
docker stop my-node-app
docker rm my-node-appBước 6: Dùng Docker Compose để quản lý dễ hơn
Tạo file docker-compose.yml:
version: "3.9"
services:
app:
build: .
container_name: my-node-app
ports:
- "3000:3000"
env_file:
- .env
restart: unless-stopped
Chạy:
docker compose up -d --buildXem log:
docker compose logs -fDừng:
docker compose down– Lệnh ngắn hơn – Dễ quản lý env, volume, network – Sau này thêm Redis, MongoDB, PostgreSQL rất tiện
Bước 7: Đưa source code lên VPS
Có 2 cách phổ biến:
Cách 1: Git clone trực tiếp trên VPS
Cài Git nếu chưa có:
apt install git -yClone project:
git clone https://github.com/yourname/your-repo.git
cd your-repoCách 2: Upload code bằng SCP/SFTP
Ví dụ:
scp -r ./my-app root@your_vps_ip:/root/Với người mới, Git clone thường tiện hơn.
Bước 8: Chạy app trên VPS bằng Docker Compose
Trong thư mục project trên VPS:
docker compose up -d --buildKiểm tra container:
docker psNếu VPS mở firewall, cho phép port app hoặc Nginx:
ufw allow 3000
ufw allow 80
ufw allow 443Test nhanh:
curl http://localhost:3000Nếu phản hồi OK → app đã chạy trên server.
Bước 9: Cấu hình Nginx làm reverse proxy
Không nên expose app Node trực tiếp cho production lâu dài. Tốt hơn: Nginx đứng trước, nhận request từ internet rồi chuyển vào container.
Cài Nginx:
apt install nginx -yTạo config:
nano /etc/nginx/sites-available/myappNội dung:
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
Kích hoạt:
ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
nginx -t
systemctl reload nginxTrỏ domain về IP VPS tại DNS. Sau vài phút, truy cập domain sẽ vào app.
Bước 10: Bật HTTPS miễn phí với Let’s Encrypt
Cài Certbot:
apt install certbot python3-certbot-nginx -yCấp SSL:
certbot --nginx -d yourdomain.com -d www.yourdomain.comCertbot sẽ tự sửa config Nginx và bật HTTPS.
Kiểm tra gia hạn tự động:
systemctl status certbot.timerKết quả: app an toàn hơn, trình duyệt không báo “Not Secure”.
Bước 11: Quy trình deploy lại khi có code mới
Khi cập nhật app:
cd your-repo
git pull
docker compose up -d --buildQuy trình này nghĩa là:
– kéo code mới – build lại image – recreate container – app chạy phiên bản mới
Nếu cần dọn image cũ:
docker image prune -aHãy cẩn thận vì lệnh này xóa image không dùng tới.
Lỗi phổ biến người mới hay gặp
Container chạy rồi nhưng web không vào được
Nguyên nhân thường là:
– app đang listen localhost thay vì 0.0.0.0
– map sai port
– firewall chặn
– Nginx proxy sai
Với Express, nên:
app.listen(3000, '0.0.0.0');npm install lỗi khi build
Thường do:
– Node version không phù hợp – package native cần build tools – lock file cũ
Fix:
– đổi image Node phù hợp, ví dụ node:20-alpine
– kiểm tra package-lock.json
– nếu cần, dùng image Debian thay Alpine
App crash ngay sau khi start
Xem log:
docker compose logs -fThường do thiếu biến môi trường hoặc DB chưa kết nối được.
Kết luận
Với người mới, deploy NodeJS lên VPS bằng Docker là lựa chọn rất đáng học. Lợi ích lớn nhất không chỉ là “chạy được”, mà là chạy ổn định, dễ lặp lại, dễ sửa lỗi. Một khi đã có Dockerfile và docker-compose.yml, bạn có thể mang app đi gần như bất kỳ VPS nào mà quy trình vẫn giống nhau.
Lộ trình thực tế nên là:
– chạy local bằng Docker – đưa lên VPS – thêm Nginx – thêm HTTPS – sau đó mới nghĩ tới CI/CD, GitHub Actions, registry, zero-downtime deploy
Nếu bạn mới bắt đầu, đừng cố tối ưu quá sớm. Chỉ cần làm đúng 3 thứ: Docker hóa app, chạy ổn trên VPS, gắn domain + HTTPS. Chừng đó đã đủ để bạn có một hệ thống production cơ bản, sạch và chuyên nghiệp hơn rất nhiều so với deploy thủ công.
Bình luận (0)
Chưa có bình luận. Hãy là người đầu tiên!