Chạy Node.js production trên VPS với PM2

Bạn vừa code xong ứng dụng Node.js, chạy ngon trên local với node app.js. Nhưng khi deploy lên VPS, nó chết bất kỳ lúc nào, crash không báo, memory leak, hoặc đơn giản là SSH bị đóng thì app cũng tắt theo. Đây là lý do bạn cần PM2, process manager chuyên nghiệp cho Node.js trong môi trường production. PM2 tự động restart khi crash, chạy cluster mode tận dụng đa nhân CPU, và cung cấp dashboard giám sát real-time. Bài viết này hướng dẫn bạn từ cài đặt, cấu hình, deploy, monitor đến xử lý lỗi trên VPS Ubuntu 24.04, mọi lệnh đều chạy được ngay.
Yêu cầu trước khi bắt đầu
- Một VPS Ubuntu 24.04 với user sudo non-root (hoặc root). Có thể thuê ngay các gói VPS giá rẻ tại thueVPS với NVMe SSD, IPv4 Việt Nam, full root.
- Node.js và npm đã được cài đặt. Nếu chưa, chạy lệnh bên dưới trước.
- Ứng dụng Node.js của bạn có file khởi động chính (ví dụ
app.jshoặcserver.js). - Cổng ứng dụng (ví dụ 3000) được mở trong UFW firewall nếu dùng.
Cài Node.js 20 LTS trên Ubuntu 24.04 (nếu chưa có):
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
Kiểm tra phiên bản:
node --version # v20.x
npm --version # 10.x
Tại sao dùng PM2 thay vì chạy node trực tiếp?
Chạy node app.js trong terminal có 3 vấn đề chết người trong production. Thứ nhất, khi bạn đóng SSH, tiến trình sẽ bị kill, ứng dụng ngừng phục vụ. Thứ hai, nếu ứng dụng crash vì lỗi uncaught exception (ví dụ lỗi kết nối database), nó chết và không tự khởi động lại. Thứ ba, trên VPS có 4 vCPU, node chỉ chạy trên 1 luồng đơn, lãng phí 75% tài nguyên.
PM2 giải quyết cả ba: chạy dưới dạng daemon (không phụ thuộc terminal), tự động restart khi crash, và có chế độ cluster mode, fork nhiều tiến trình con, mỗi tiến trình chạy trên một nhân CPU. Nó còn tích hợp log rotation, health check, và web dashboard.
Bước 1, Cài đặt PM2
Cài PM2 toàn cục qua npm:
sudo npm install -g pm2
Kiểm tra phiên bản và help:
pm2 --version # 5.x trở lên
pm2 --help
Lưu ý: dùng sudo npm install -g để PM2 có quyền ghi vào /usr/local/lib và tạo systemd service sau này. Không dùng npm install pm2 cục bộ trong project.
Bước 2, Khởi động ứng dụng Node.js với PM2
Giả sử bạn có ứng dụng đơn giản app.js lắng nghe port 3000. Di chuyển vào thư mục project:
cd /home/youruser/myapp
Khởi động với PM2:
pm2 start app.js --name my-app
Giải thích: --name đặt tên cho tiến trình để dễ quản lý. Nếu không đặt, PM2 lấy tên file.
Kiểm tra trạng thái:
pm2 status
Kết quả mong đợi, bảng hiển thị process "my-app", status "online", mode "fork", uptime > 0s.
| Column | Mô tả |
|---|---|
| id | Số thứ tự process (0, 1, 2...) |
| name | Tên bạn đặt với --name |
| mode | fork (đơn tiến trình) hoặc cluster |
| status | online, stopped, errored |
| restarts | Số lần tự động restart |
| uptime | Thời gian chạy liên tục |
Bước 3, Cluster mode: tận dụng đa nhân CPU
VPS thường có 2, 4 hoặc 8 vCPU. Chạy fork mode chỉ dùng 1 nhân. Cluster mode fork nhiều worker, mỗi worker chịu một phần request, tăng throughput.
Khởi động cluster mode với số instance bằng số CPU cores:
pm2 start app.js -i max --name my-app
Giải thích: -i max tự động tạo số instance bằng số CPU cores. Bạn có thể ghi rõ số (vd -i 4).
Kiểm tra:
pm2 status
Lúc này bảng sẽ hiện 4 dòng (nếu VPS có 4 cores), mode "cluster". Mỗi instance chạy trên port khác nhau, PM2 tự động load balance qua round-robin.
Lưu ý: Cluster mode yêu cầu ứng dụng của bạn stateless, không lưu session trong memory (dùng Redis, database). Nếu app có state (ví dụ socket.io với sticky session), cần thêm flag --instances max --max-memory-restart 500M --merge-logs và cấu hình nginx upstream với ip_hash.
Bước 4, Thiết lập auto-start với systemd
Khi VPS reboot (ví dụ bảo trì hạ tầng, cập nhật kernel), PM2 tự động khởi động lại tất cả ứng dụng nhờ systemd service.
Dùng lệnh sau để generate và enable service:
pm2 startup systemd
Lệnh này sẽ hiển thị một dòng lệnh systemd, yêu cầu bạn chạy với sudo. Copy-paste dòng đó. Ví dụ:
sudo env PATH=$PATH:/usr/bin pm2 startup systemd -u youruser --hp /home/youruser
Lưu danh sách process hiện tại:
pm2 save
Kiểm tra service:
systemctl status pm2-youruser
Output mong đợi: active (running), enabled. Nếu chưa enabled, chạy sudo systemctl enable pm2-youruser.
Test thử: reboot VPS và kiểm tra pm2 status sau khi khởi động lại.
Bước 5, Ecosystem file: cấu hình dự án chuẩn hóa
Thay vì gõ lệnh mỗi lần, bạn nên tạo file ecosystem.config.js trong thư mục project. File này chứa toàn bộ cấu hình: name, script, mode, biến môi trường, log, memory limit.
Tạo file:
nano ecosystem.config.js
Nội dung mẫu:
module.exports = {
apps : [{
name: 'my-app',
script: 'app.js',
instances: 'max',
exec_mode: 'cluster',
watch: false,
max_memory_restart: '500M',
env: {
NODE_ENV: 'production',
PORT: 3000
},
error_file: './logs/err.log',
out_file: './logs/out.log',
log_date_format: 'YYYY-MM-DD HH:mm:ss Z'
}]
};
Giải thích từng field:
instances: 'max', tự động cluster số core.exec_mode: 'cluster', bật cluster mode.max_memory_restart: '500M', nếu process dùng RAM vượt 500MB, PM2 tự động restart. Ngăn memory leak.env, biến môi trường cho production.error_file/out_file, ghi log riêng, dễ debug.watch: false, tắt watch mode trong production (chỉ dùng cho dev).
Khởi động bằng ecosystem file:
pm2 start ecosystem.config.js
Để reload (zero-downtime nếu có cluster):
pm2 reload ecosystem.config.js
Bước 6, Giám sát ứng dụng với pm2 monit và pm2 log
Theo dõi real-time CPU, memory, request của từng instance:
pm2 monit
Giao diện terminal hiển thị: CPU%, memory (MB), uptime, log stream. Nhấn Ctrl+C để thoát.
Xem log (stdout và stderr) của tất cả process hoặc của 1 app:
pm2 logs # all apps
pm2 logs my-app # chỉ my-app
pm2 logs --lines 100 # 100 dòng gần nhất
Để clear log file:
pm2 flush
Nếu bạn muốn dashboard web (tích hợp sẵn, không cần cài thêm):
Xử lý lỗi thường gặp
Lỗi 1: "pm2: command not found" sau khi reboot
Nguyên nhân: chưa chạy pm2 startup hoặc pm2 save. Chạy lại 2 lệnh theo đúng thứ tự: pm2 startup systemd, copy lệnh sudo, pm2 save.
Lỗi 2: "Error: listen EADDRINUSE :::3000"
Cổng 3000 đã có process khác chiếm. Kiểm tra với ss -tlnp | grep :3000 hoặc kill process cũ: pm2 delete my-app rồi start lại. Nếu chạy cluster mode, PM2 tự động phân phối port, lỗi này thường xảy ra nếu app không được code đúng để PM2 inject port.
Lỗi 3: Ứng dụng crash liên tục, PM2 restart loop
Xem log với pm2 logs my-app --lines 50 để tìm lỗi JavaScript. Sau đó fix code và reload. Nếu lỗi là hết RAM (OOM), tăng max_memory_restart trong ecosystem file hoặc nâng cấp VPS. Các gói VPS Linux tại thueVPS có RAM từ 2GB trở lên phù hợp cho Node.js production.
Lỗi 4: "pm2: command not found" khi dùng sudo
PM2 cài qua npm global thường ở /usr/local/bin. Nếu sudo không thấy, dùng full path: sudo /usr/local/bin/pm2 list. Hoặc cài lại gọn: sudo npm install -g pm2.
Câu hỏi thường gặp
PM2 có dùng được cho Python, Ruby hay Go không?
Có. PM2 không giới hạn Node.js, bạn có thể chạy script Python, Ruby, binary Go, thậm chí PHP với flag --interpreter. Ví dụ: pm2 start python app.py --interpreter python3. Nhưng chức năng cluster mode chỉ hoạt động hàng đầu với Node.js.
Làm sao để cập nhật ứng dụng Node.js mà không downtime?
Dùng pm2 reload ecosystem.config.js (nếu đang cluster mode). PM2 sẽ gracefully restart từng instance, luôn có ít nhất 1 instance phục vụ request. Với fork mode (1 instance), dùng pm2 restart my-app, sẽ có vài giây downtime.
PM2 có tự động dọn log không? Làm sao để log không đầy disk?
PM2 không dọn log tự động. Bạn nên dùng pm2-logrotate để rotate log. Cài: pm2 install pm2-logrotate. Cấu hình max size (vd 10M) và retention (vd 7 ngày). Hoặc dùng logrotate của hệ thống kết hợp với thư mục log tùy chỉnh.
Có nên chạy PM2 với Docker không?
Có thể, nhưng không khuyến khích. Docker đã có restart policy riêng. Nếu bạn chạy Node.js trong container, dùng docker run --restart always. Chỉ dùng PM2 trong Docker nếu cần cluster mode và log management phức tạp.
Port mặc định 3000 có an toàn không? Nên đưa ra port 80/443 như thế nào?
Port 3000 chỉ nên dùng cho internal. Đưa ra internet qua nginx reverse proxy: cấu hình proxy_pass http://localhost:3000 và dùng Certbot SSL. Xem bài Cấu hình Nginx làm reverse proxy trên Ubuntu 24.04 để chi tiết.
Làm sao để PM2 gửi cảnh báo khi process crash?
PM2 plus (Keymetrics) có tính năng này. Hoặc bạn tự viết script Bash check pm2 status định kỳ qua cron và gửi Telegram, tham khảo Hướng dẫn gửi cảnh báo hệ thống VPS qua Telegram bot.
Bài viết liên quan
- Cách cài Docker trên VPS Ubuntu chi tiết từ A đến Z
- Tối ưu Nginx cho traffic cao, worker, gzip, buffer, cache
- Hướng dẫn cài đặt Redis cache cho ứng dụng web trên VPS
- Cài đặt LEMP stack Nginx MariaDB PHP 8.3 trên Ubuntu 24.04


