Tự Động Deploy NodeJS Lên VPS Bằng Docker Và GitHub Actions

08/05/2026 · P T P · Chung

Tự động deploy NodeJS bằng Docker trên VPS với GitHub Actions: nhanh, sạch, ít lỗi

Deploy thủ công thường bắt đầu rất “ổn”: SSH vào VPS, git pull, npm install, restart app. Nhưng chỉ vài lần là lộ vấn đề: quên pull đúng branch, quên migrate, lệch môi trường, downtime lúc restart, “máy em chạy được”. Quy trình nhỏ → rủi ro lớn.

Giải pháp gọn, thực dụng: đóng gói app NodeJS bằng Docker, đẩy code lên GitHub, dùng GitHub Actions để tự động build và deploy lên VPS. Kết quả: mỗi lần push → pipeline chạy → VPS cập nhật đồng nhất, dễ rollback, dễ mở rộng.

Bài này đi theo hướng thực chiến: ít lý thuyết, tập trung thứ bạn cần để chạy được.

Vì sao nên kết hợp Docker + VPS + GitHub Actions?

Docker → môi trường đồng nhất

NodeJS rất hay dính lỗi kiểu:

– local Node 20, server Node 18
– local có package, server thiếu
– app phụ thuộc binary/native module khác OS

Docker giải quyết bằng cách đóng gói app + runtime + dependency thành image. Local chạy sao, server chạy gần như vậy.

VPS → rẻ, chủ động, đủ mạnh cho nhiều dự án

Với app vừa và nhỏ, VPS thường là lựa chọn cân bằng:

rẻ hơn PaaS
toàn quyền cài Nginx, Docker, firewall
– dễ host nhiều service trên cùng máy

Đổi lại: bạn phải tự lo deploy, bảo mật, backup. GitHub Actions giúp giảm mạnh phần “tay chân”.

GitHub Actions → CI/CD ngay trong repo

Không cần dựng Jenkins hay GitLab Runner riêng. Chỉ cần file workflow là có thể:

– chạy test
– build image
– SSH vào VPS
– pull code/image
– restart container

Push codedeploy tự động. Nhất quán, ít quên bước.

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

Một flow phổ biến, dễ áp dụng:

1. Dev push code lên branch main
2. GitHub Actions được kích hoạt
3. Workflow SSH vào VPS
4. VPS pull code mới hoặc nhận lệnh cập nhật
5. Docker Compose rebuild/restart container
6. App NodeJS chạy phiên bản mới

Có 2 hướng chính:

Hướng A: build ngay trên VPS
– đơn giản
– không cần registry
– hợp dự án nhỏ

Hướng B: build image trên GitHub Actions, push lên registry rồi VPS pull
– sạch hơn
– deploy nhanh hơn
– hợp team/prod

Trong bài này, ưu tiên Hướng A vì dễ bắt đầu nhất.

Chuẩn bị trên VPS

Trên VPS Ubuntu, cài Docker và Docker Compose plugin:

sudo apt update
sudo apt install -y docker.io docker-compose-plugin git
sudo systemctl enable docker
sudo systemctl start docker

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

sudo usermod -aG docker $USER

Đăng xuất rồi đăng nhập lại.

Tiếp theo, clone project về thư mục deploy, ví dụ:

mkdir -p /var/www/myapp
cd /var/www/myapp
git clone https://github.com/yourname/your-repo.git .

Nếu app dùng file môi trường, tạo .env ngay trên VPS:

PORT=3000
NODE_ENV=production
DATABASE_URL=...
JWT_SECRET=...

Không commit .env lên GitHub.

Dockerize ứng dụng NodeJS

Dockerfile cơ bản

Tạo file Dockerfile:

FROM node:20-alpine

WORKDIR /app

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

COPY . .

EXPOSE 3000

CMD ["npm", "start"]

Ý nghĩa:

node:20-alpine → image nhẹ
npm ci → cài dependency ổn định theo lockfile
--omit=dev → production gọn hơn

Nếu app cần build, ví dụ TypeScript/NestJS, có thể dùng multi-stage build. Nhưng với nhiều app Express/Fastify đơn giản, file trên là đủ.

docker-compose.yml

Tạo docker-compose.yml:

version: "3.9"

services: app: build: . container_name: myapp restart: always ports: - "3000:3000" env_file: - .env

Chạy thử trên VPS:

docker compose up -d --build

Kiểm tra:

docker ps
docker logs -f myapp

Nếu app chạy ổn tại đây, phần khó nhất đã qua.

Cấu hình SSH an toàn cho GitHub Actions

Để GitHub Actions SSH vào VPS, nên dùng SSH key, không dùng password.

Trên máy local, tạo key:

ssh-keygen -t ed25519 -C "github-actions-deploy"

Copy public key lên VPS:

ssh-copy-id user@your_vps_ip

Hoặc tự thêm nội dung file .pub vào:

~/.ssh/authorized_keys

Sau đó, vào GitHub repo → SettingsSecrets and variablesActions, thêm các secret:

VPS_HOST → IP/domain VPS
VPS_USER → user SSH
VPS_SSH_KEY → nội dung private key
VPS_PORT → thường là 22

Nếu dùng .env sinh động từ CI, có thể thêm secret DB/auth tương ứng. Nhưng dễ nhất vẫn là giữ .env trên VPS.

Tạo workflow GitHub Actions để deploy tự động

Tạo file:

.github/workflows/deploy.yml

Nội dung:

name: Deploy NodeJS to VPS

on: push: branches: - main

jobs: deploy: runs-on: ubuntu-latest

steps: - name: Deploy via SSH uses: appleboy/[email protected] with: host: ${{ secrets.VPS_HOST }} username: ${{ secrets.VPS_USER }} key: ${{ secrets.VPS_SSH_KEY }} port: ${{ secrets.VPS_PORT }} script: | cd /var/www/myapp git pull origin main docker compose down docker compose up -d --build docker image prune -f

Flow này rất rõ:

push main → trigger
– GitHub Actions SSH vào VPS
git pull → lấy code mới
docker compose up -d --build → rebuild + chạy lại

Nếu muốn giảm downtime, có thể bỏ docker compose down và dùng:

docker compose up -d --build

Compose sẽ recreate service khi cần. Thực tế ổn hơn cho app nhỏ.

Reverse proxy và domain: nên có

Chạy trực tiếp cổng 3000 được, nhưng production nên đặt Nginx phía trước:

– map domain
– SSL với Let’s Encrypt
– gzip/cache header
– ẩn app port nội bộ

Ví dụ Nginx reverse proxy tới localhost:3000. Khi đó user chỉ truy cập https://yourdomain.com, còn container vẫn giữ cổng riêng.

Nếu bạn đã có Nginx ngoài Docker, mô hình sẽ gọn: Nginx hostNode container.

Một số cải tiến đáng giá

Thêm bước test trước deploy

Deploy mọi commit lên production mà không test → rủi ro. Có thể thêm:

- uses: actions/checkout@v4
- uses: actions/setup-node@v4
  with:
    node-version: 20
- run: npm ci
- run: npm test

test fail → không deploy.

Healthcheck

App khởi động lỗi mà container vẫn restart liên tục → khó nhận biết. Nên có route /health và healthcheck trong Docker.

Tách môi trường staging/prod

main → production
develop → staging

Mỗi branch → 1 workflow hoặc 1 VPS khác. Team làm việc an toàn hơn.

Rollback

Cách đơn giản nhất khi deploy kiểu pull code trên VPS:

git log --oneline
git checkout <commit>
docker compose up -d --build

Không “đẹp” bằng rollback theo image tag, nhưng đủ cứu production lúc gấp.

Lỗi thường gặp

Permission denied (publickey)

Nguyên nhân:

– sai private key trong GitHub Secret
– user SSH sai
– public key chưa nằm trong authorized_keys

Fix: test SSH từ local trước, rồi copy đúng private key vào secret.

docker: permission denied

User deploy chưa thuộc group docker.

Fix:

sudo usermod -aG docker $USER

Đăng nhập lại.

Container build được nhưng app crash

Thường do:

– thiếu biến môi trường
npm start sai command
– app bind sai host/port

Với NodeJS, nên bảo đảm app listen trên 0.0.0.0, không phải chỉ localhost.

Ví dụ:

app.listen(process.env.PORT || 3000, '0.0.0.0');

git pull bị conflict trên VPS

Nguyên nhân: bạn sửa file trực tiếp trên server.

Fix: tránh sửa code trên VPS. Server chỉ nên là nơi chạy app. Config tách qua .env, Nginx, secret.

Kết luận

Nếu bạn muốn một quy trình deploy gọn, rẻ, dễ kiểm soát, bộ ba NodeJS + Docker + VPS + GitHub Actions là lựa chọn rất mạnh. Nó không quá phức tạp như Kubernetes, nhưng chuyên nghiệp hơn hẳn việc SSH tay mỗi lần release.

Công thức cốt lõi:

Docker → đồng nhất môi trường
VPS → chủ động hạ tầng
GitHub Actions → tự động hóa deploy
SSH + Compose → triển khai nhanh, dễ hiểu

Điểm quan trọng nhất không phải “xịn” đến đâu, mà là ổn định và lặp lại được. Một pipeline đơn giản, chạy chắc, luôn tốt hơn quy trình cầu kỳ nhưng khó bảo trì.

Nếu bạn mới bắt đầu, hãy triển khai phiên bản tối thiểu:

1. Dockerize app
2. Chạy ổn trên VPS bằng Compose
3. Tạo SSH key
4. Viết workflow GitHub Actions
5. Push một commit thử nghiệm

Chỉ cần vậy, bạn đã có CI/CD thực dụng cho dự án NodeJS. Từ đó, mới nâng cấp dần: test, healthcheck, rollback, registry, zero-downtime. Làm từng bước → ít lỗi, dễ vận hành, dễ ngủ ngon hơn sau mỗi lần deploy.

#bang #deploy #docker #dong #nodejs
Chia sẻ:
← Trước
PM2 hay Docker trên VPS: Cách Deploy NodeJS Tối Ưu Nhất
Sau →
Cách Giám Sát Log Và Tài Nguyên NodeJS Docker Trên VPS Hiệu Quả

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!