5 bước deploy Node.js lên VPS Ubuntu (dùng Nginx & PM2)

Tác giả: Trần Thảo 08 tháng 02, 2026

Bạn vừa hoàn thành một ứng dụng Node.js (dùng Express.js, NestJS,…) và nó chạy ổn định trên localhost:3000. Nhưng làm thế nào để đưa ứng dụng này lên Internet một cách chuyên nghiệp, cho phép người dùng truy cập ổn định, bảo mật và tự động khởi động lại khi có lỗi?

Bạn không thể chỉ SSH vào VPS rồi chạy node app.js. Ngay khi bạn đóng terminal, ứng dụng sẽ ngừng hoạt động.

Bài viết này sẽ hướng dẫn bạn toàn bộ quy trình 5 bước chuẩn mực để deploy Node.js lên VPS Ubuntu. Chúng ta sẽ sử dụng bộ ba công cụ tiêu chuẩn vàng của ngành: Nginx làm Reverse Proxy, PM2 để quản lý tiến trình và Certbot cho SSL.

Nếu bạn quan tâm đến một phương pháp deploy khác bằng container, bạn có thể tham khảo Hướng Dẫn Cài Đặt Docker Trên VPS Ubuntu Dành Cho Người Mới Bắt Đầu.

Mô hình DevOps Team Deploy Nodejs

Tóm tắt 5 bước chính:

  1. Cài đặt môi trường: Cài Nginx (proxy), NVM (quản lý Node.js), và PM2 (quản lý tiến trình).
  2. Tải code & cài đặt: Clone dự án từ Git về VPS và chạy npm ci --production.
  3. Chạy với PM2: Dùng file ecosystem.config.js để khởi động ứng dụng và cấu hình tự khởi động lại (auto-restart).
  4. Cấu hình Nginx: Tạo file config để Nginx làm reverse proxy, chuyển tiếp request từ port 80/443 đến port Node.js (ví dụ: 3000).
  5. Cài đặt SSL: Dùng Certbot để cài đặt HTTPS miễn phí, tự động chuyển hướng HTTP sang HTTPS.

Tại sao phải dùng Nginx và PM2?

Trước khi đi vào các bước, hãy làm rõ vai trò của từng thành phần trong hệ thống:

  • VPS Ubuntu: Máy chủ ảo (Virtual Private Server) chạy hệ điều hành Ubuntu, nơi lưu trữ và vận hành ứng dụng.
  • Nginx (Reverse Proxy): Ứng dụng Node.js của bạn chạy ở port nội bộ (ví dụ 3000). Nginx sẽ đứng ở cổng giao tiếp (port 80 và 443), nhận mọi yêu cầu từ người dùng và chuyển tiếp (proxy) một cách thông minh đến ứng dụng. Nó cũng xử lý SSL (HTTPS) và phục vụ file tĩnh với hiệu suất cao.
  • PM2 (Process Manager): PM2 là một Trình quản lý Tiến trình cho Node.js, hoạt động như một hệ thống giám sát 24/7. Nhiệm vụ của nó bao gồm:
    • Đảm bảo ứng dụng Node.js luôn ở trạng thái Active (Đang hoạt động).
    • Tự động khởi động lại (restart) ngay lập tức nếu ứng dụng gặp sự cố (crash).
    • Quản lý nhật ký (logs) tập trung.
    • Tự khởi động cùng VPS khi máy chủ reboot.
    • Cho phép chạy ứng dụng ở chế độ Cluster (tận dụng đa nhân CPU).
    • Ngoài web app, PM2 còn rất mạnh mẽ, ví dụ như dùng để vận hành bot Telegram trên VPS Linux 24/7.

Chuẩn bị (Điều kiện tiên quyết)

Để thực hiện hướng dẫn này, bạn cần:

  1. Một VPS Ubuntu: Đã cài đặt phiên bản 20.04 hoặc 22.04 LTS.
  2. Truy cập SSH: Bạn có thể SSH vào VPS với quyền sudo.
  3. Một tên miền (Domain): Đã trỏ A Record về địa chỉ IP của VPS.
  4. Mã nguồn ứng dụng: Đã được đẩy lên một kho lưu trữ Git (như GitHub, GitLab).
  5. Kiến thức cơ bản: Về dòng lệnh Linux. (Nếu bạn mới bắt đầu, hãy tham khảo bài Tổng hợp 20+ lệnh Linux cơ bản nhất cho người mới dùng VPS).

Bước 1: Cài đặt môi trường (Nginx, Git, NVM, PM2)

Đầu tiên, chúng ta cần thiết lập VPS với các công cụ cần thiết.

Cập nhật hệ thống

Luôn bắt đầu bằng việc cập nhật các gói phần mềm của hệ thống để đảm bảo tính bảo mật và ổn định:

sudo apt update && sudo apt upgrade -y

Cài đặt Nginx và Git

Cài đặt Nginx làm proxy server và Git để tải mã nguồn về:

sudo apt install nginx git -y

Để xem hướng dẫn cài đặt Git chi tiết hơn, bạn có thể tham khảo bài viết Cách cài đặt Git trên VPS Linux.

Cài đặt Node.js (Qua NVM)

Cách chuyên nghiệp để cài đặt Node.js là dùng NVM (Node Version Manager). NVM cho phép bạn cài đặt và quản lý nhiều phiên bản Node.js khác nhau trên cùng một máy chủ một cách linh hoạt.

Chạy lệnh sau để tải và cài đặt NVM (phiên bản v0.40.3):

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash

Tiếp theo, chạy lệnh sau để kích hoạt biến môi trường NVM trong phiên terminal hiện tại:

export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"

Bây giờ, hãy cài đặt phiên bản Node.js LTS (Long Term Support) mới nhất. Đây sẽ là phiên bản mặc định trên máy chủ của bạn:

nvm install --lts

Bạn có thể kiểm tra lại phiên bản Node và NPM bằng lệnh: node -vnpm -v.

Cài đặt PM2

Cuối cùng, cài đặt PM2 – trình quản lý tiến trình – với quyền quản trị toàn cục (global) qua NPM:

npm install pm2@latest -g

Bước 2: Tải code và cấu hình dự án

Môi trường đã sẵn sàng, giờ là lúc triển khai mã nguồn lên VPS.

Clone dự án từ Git

Chúng ta sẽ lưu trữ mã nguồn web trong thư mục tiêu chuẩn /var/www/. Hãy tạo thư mục dự án và clone code:

# 1. Tạo thư mục và cấp quyền sở hữu cho user hiện tại
sudo mkdir -p /var/www/my-project
sudo chown -R $USER:$USER /var/www/my-project

# 2. Di chuyển vào thư mục và clone mã nguồn
cd /var/www/my-project
git clone https://github.com/your-username/your-repo.git .

Lưu ý: Dấu . ở cuối lệnh git clone dùng để clone mã nguồn trực tiếp vào thư mục hiện tại mà không tạo thêm thư mục con.

Cài đặt Dependencies

Cài đặt các gói node_modules cần thiết. Chúng ta dùng lệnh npm ci (Clean Install) để cài đặt chính xác các phiên bản từ file package-lock.json, tối ưu cho môi trường Production:

npm ci --production

Cấu hình môi trường (.env và .nvmrc)

Hầu hết các ứng dụng cần file .env để lưu trữ thông tin nhạy cảm. Hãy tạo và chỉnh sửa file .env:

nano .env

Dán các biến môi trường của bạn vào file, đặc biệt lưu ý biến PORT:

NODE_ENV=production
PORT=3000
DATABASE_URL="your_database_connection_string"
JWT_SECRET="your_super_secret_key"

Port 3000 là thông số quan trọng, sẽ được sử dụng để cấu hình Nginx ở bước sau.

Thực hành tốt nhất (Best Practice): Tạo file .nvmrc để cố định phiên bản Node.js cho dự án. Điều này đảm bảo PM2 luôn sử dụng đúng phiên bản Runtime.

# Lấy phiên bản Node hiện tại và ghi vào file cấu hình
nvm current > .nvmrc

Bước 3: Chạy ứng dụng với PM2 (Process Manager)

Đã đến lúc khởi động ứng dụng với PM2. Thay vì dùng lệnh pm2 start app.js thủ công, chúng ta sẽ dùng file ecosystem.config.js để quản lý cấu hình chuyên nghiệp hơn.

Tạo file Ecosystem

Tạo file cấu hình ecosystem.config.js trong thư mục gốc của dự án:

nano ecosystem.config.js

Dán nội dung cấu hình dưới đây vào file:

// ecosystem.config.js
module.exports = {
  apps : [{
    name   : "my-app",         // Tên định danh ứng dụng trong PM2
    script : "app.js",         // File khởi chạy (entry point: app.js, index.js...)
    interpreter: "node",       // Chỉ định PM2 dùng Node interpreter
    // Đường dẫn tuyệt đối đến phiên bản Node do NVM quản lý
    interpreter_args: "~/.nvm/versions/node/$(nvm current)/bin/node", 
    
    // Cấu hình biến môi trường cho production
    env_production: {
        NODE_ENV: "production",
        PORT: 3000 // Phải khớp với file .env và cấu hình Nginx
    }
  }]
}

Lưu ý kỹ thuật: Tham số interpreter_args giúp ép buộc PM2 sử dụng chính xác phiên bản Node.js đã cài qua NVM, tránh xung đột phiên bản hệ thống.

Khởi động ứng dụng

Khởi chạy ứng dụng thông qua file cấu hình vừa tạo:

pm2 start ecosystem.config.js --env production

Kiểm tra trạng thái ứng dụng bằng lệnh: pm2 list. Bạn sẽ thấy ứng dụng “my-app” đang ở trạng thái online.

Cấu hình tự khởi động khi Reboot

Lệnh sau sẽ tạo script để PM2 tự động khởi động lại các ứng dụng mỗi khi VPS reboot:

pm2 startup

PM2 sẽ hiển thị một dòng lệnh trên màn hình terminal (thường bắt đầu bằng sudo env...). Bạn hãy copy và chạy dòng lệnh đó.

Sau khi chạy xong, lưu lại danh sách tiến trình hiện tại để PM2 ghi nhớ:

pm2 save

Các lệnh PM2 hữu ích

  • Xem logs (Gỡ lỗi/Debug): pm2 logs my-app
  • Cập nhật code (Zero-Downtime):
    cd /var/www/my-project
    git pull
    npm ci --production
    pm2 reload my-app

Bước 4: Cấu hình Nginx (Reverse Proxy)

Mô hình hoạt động Reverse Proxy Nginx

Hiện tại, ứng dụng đang chạy ở localhost:3000 (mạng nội bộ). Để người dùng truy cập được từ Internet qua port 80/443, chúng ta cần cấu hình Nginx làm Reverse Proxy.

Để hiểu sâu hơn về cơ chế hoạt động, bạn có thể tham khảo bài viết chuyên sâu: Cách định cấu hình Nginx làm Proxy ngược trên VPS Linux Ubuntu.

Tạo file cấu hình Nginx

Tạo một file cấu hình mới (Virtual Host) cho tên miền:

sudo nano /etc/nginx/sites-available/your-domain.com

Thiết lập Reverse Proxy

Dưới đây là cấu hình tiêu chuẩn để deploy Node.js, bao gồm hỗ trợ WebSockets (cần thiết cho các ứng dụng dùng Socket.io).
Thay your-domain.com bằng tên miền thực tế và 3000 bằng port ứng dụng của bạn.

server {
    listen 80;
    listen [::]:80;

    server_name your-domain.com www.your-domain.com; 

    access_log /var/log/nginx/your-domain.com.access.log;
    error_log /var/log/nginx/your-domain.com.error.log;

    location / {
        # Chuyển tiếp yêu cầu đến ứng dụng Node.js nội bộ
        proxy_pass http://localhost:3000; 

        # Bao gồm các header proxy tiêu chuẩn
        include proxy_params;

        # Cấu hình header cho WebSockets
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        
        # Chuyển header Host để ứng dụng nhận diện được domain gốc
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}

Nhấn CTRL+O để lưu file và CTRL+X để thoát trình soạn thảo.

Kích hoạt cấu hình

Tạo liên kết tượng trưng (symbolic link) để kích hoạt file cấu hình:

# 1. Tạo link sang thư mục sites-enabled
sudo ln -s /etc/nginx/sites-available/your-domain.com /etc/nginx/sites-enabled/

# 2. (Tùy chọn) Xóa cấu hình mặc định nếu không dùng
sudo rm /etc/nginx/sites-enabled/default

Kiểm tra cú pháp cấu hình Nginx:

sudo nginx -t

Nếu hệ thống trả về syntax is oktest is successful nghĩa là cấu hình hợp lệ.

Mở Firewall và khởi động lại Nginx

Cấu hình tường lửa UFW cho phép lưu lượng truy cập HTTP/HTTPS.

sudo ufw allow 'Nginx Full'

Khởi động lại Nginx để áp dụng thay đổi:

sudo systemctl restart nginx

Lúc này, hãy truy cập http://your-domain.com để kiểm tra kết quả.

Bước 5: Cài đặt SSL (HTTPS) với Certbot

Bảo mật SSL HTTPS Encryption

Để đảm bảo an toàn dữ liệu và tối ưu SEO, bước cuối cùng là cài đặt chứng chỉ SSL miễn phí từ Let’s Encrypt. Phương pháp ổn định nhất trên Ubuntu là sử dụng snap.

Cài đặt Certbot bằng Snap

# Cài đặt core snap
sudo snap install core; sudo snap refresh core

# Cài đặt Certbot
sudo snap install --classic certbot

# Tạo liên kết lệnh
sudo ln -s /snap/bin/certbot /usr/bin/certbot

Kích hoạt SSL cho Domain

Chạy lệnh sau và làm theo hướng dẫn trên màn hình:

sudo certbot --nginx -d your-domain.com -d www.your-domain.com

Trong quá trình cài đặt:

  • Nhập email quản trị để nhận thông báo bảo mật.
  • Đồng ý với các điều khoản dịch vụ.
  • Quan trọng: Khi được hỏi về cấu hình chuyển hướng, hãy chọn 2 (Redirect) để tự động chuyển toàn bộ truy cập HTTP sang HTTPS.

Sau khi hoàn tất, hãy truy cập https://your-domain.com. Bạn sẽ thấy biểu tượng ổ khóa bảo mật trên thanh địa chỉ.

Kiểm tra cơ chế tự động gia hạn

Chứng chỉ Let’s Encrypt có hiệu lực 90 ngày. Gói Snap đã tự động cấu hình việc gia hạn, bạn chỉ cần kiểm tra bằng lệnh giả lập (dry-run):

sudo certbot renew --dry-run

Nếu không có lỗi xuất hiện, hệ thống SSL của bạn đã được cấu hình tự động hoàn toàn.

Xử lý lỗi thường gặp (Troubleshooting)

Lỗi 1: 502 Bad Gateway

Đây là lỗi phổ biến nhất, cho thấy Nginx không thể kết nối được với ứng dụng Node.js (tại port 3000).

  • Kiểm tra PM2: Chạy pm2 list. Nếu trạng thái là stopped hoặc errored, hãy xem chi tiết lỗi bằng pm2 logs my-app.
  • Kiểm tra Port: Đối chiếu port trong proxy_pass (file cấu hình Nginx) xem có khớp với port trong ecosystem.config.js và file .env không.
  • Kiểm tra Log Nginx: Xem log lỗi của web server: sudo tail -f /var/log/nginx/your-domain.com.error.log.

Lỗi 2: Lỗi npm ci thất bại

Nếu dự án sử dụng các thư viện cần biên dịch Native Module (C++) như bcrypt, sharp, quá trình cài đặt có thể bị lỗi do thiếu công cụ biên dịch.

  • Giải pháp: Cài đặt gói công cụ build: sudo apt install build-essential -y sau đó chạy lại npm ci --production.

Kết luận

Bảo trì hệ thống Website VPS

Chúc mừng bạn! Bạn đã hoàn thành quy trình deploy Node.js lên VPS Ubuntu theo tiêu chuẩn kỹ thuật cao.

Bạn đã xây dựng một hệ thống hoàn chỉnh: từ cài đặt môi trường (NVM, PM2, Nginx), triển khai mã nguồn (Git), đảm bảo tính sẵn sàng cao (PM2 Ecosystem), tối ưu hiệu suất (Nginx Reverse Proxy), và bảo mật dữ liệu (SSL/HTTPS). Đây là nền tảng vững chắc để vận hành các ứng dụng Node.js quy mô lớn.

Nếu bạn gặp bất kỳ vấn đề kỹ thuật nào trong quá trình thực hiện, hãy để lại bình luận bên dưới để được hỗ trợ!

Tài liệu tham khảo