Setup PM2 cho Node.js production trên VPS: auto-restart, log rotation

Mục lục
TL;DR
  • PM2 là process manager chuẩn vàng cho Node.js production: auto-restart khi crash, cluster mode tận dụng multi-core, log rotation tự động.
  • Cài 30 giây bằng npm. Start app: pm2 start "npm run start" --name myapp. Khởi động cùng OS: pm2 startup + pm2 save.
  • Cluster mode chia traffic ra N worker (= số CPU core), giúp Node tận dụng full CPU thay vì 1 core.
  • pm2-logrotate plugin rotate log mỗi ngày, giữ 7 ngày, max 50MB/file, gzip cũ.
  • Bài này hướng dẫn full: install, start, cluster, log, monit, ecosystem.config.js, zero-downtime reload, debug khi app crash loop.

Node.js single-threaded, một app crash là dừng hoàn toàn. Trên VPS production, bạn không thể SSH vào restart mỗi lần memory leak hoặc unhandled promise. PM2 giải quyết bài toán này: theo dõi app, auto-restart khi crash, multiplex traffic qua nhiều worker, rotate log để disk không full. Đây là tool số 1 mà dev Node nên cài trên mỗi VPS production.

Bài này hướng dẫn từ A đến Z: cài PM2, start app đơn, mở cluster mode, cấu hình log rotation, viết ecosystem.config.js cho multi-app, zero-downtime reload khi deploy, debug khi app rơi vào crash loop. Tất cả test trên Cloud VPS 50 với Node.js 22 LTS và Ubuntu 24.04.

PM2 là gì và tại sao dùng?

PM2 (Process Manager 2) là daemon viết bằng Node.js do KeyMetrics phát triển từ 2013. Nó wrap một hoặc nhiều Node app, làm:

  • Auto-restart khi crash, kèm exponential backoff để tránh loop CPU 100 phần trăm.
  • Cluster mode: chạy N worker, load balance traffic qua chúng (built-in của Node http server).
  • Log management: capture stdout/stderr ra file, rotate hằng ngày.
  • Health monitoring: CPU, RAM, uptime mỗi process.
  • Khởi động cùng OS: tạo systemd unit tự động.
  • Zero-downtime reload: cập nhật code mới không drop request.

Alternative: systemd unit riêng cho mỗi app (verbose hơn), Forever (đã cũ), Nodemon (chỉ dev), Docker (overkill cho app nhỏ). PM2 cân bằng tốt nhất cho dev solo và team nhỏ.

Bước 1: Cài PM2

sudo npm install -g pm2
pm2 --version
which pm2

Nếu chưa có Node, cài qua nodesource hoặc nvm:

curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs

Bước 2: Start app đơn giản

cd /var/www/myapp
pm2 start "npm run start" --name myapp
pm2 status

Output bảng status: pid, status (online), restart count, CPU, mem. App đã chạy background, console của bạn rảnh để làm việc khác.

Test crash auto-restart:

kill -9 $(pm2 pid myapp)
pm2 status

Sau 1-2 giây, PM2 đã restart app. Restart count tăng lên 1.

Bước 3: Khởi động cùng OS (systemd integration)

pm2 startup
# Copy lệnh PM2 in ra, paste và chạy (cần sudo)
pm2 save

Lệnh đầu sinh ra systemd unit file. Lệnh sau lưu state hiện tại của PM2 (danh sách app đang chạy). Sau reboot VPS, systemd start PM2, PM2 đọc state đã save và start lại các app. Hoàn toàn tự động, không cần can thiệp.

Bước 4: Cluster mode tận dụng multi-core

pm2 start "npm run start" --name myapp -i max
# Hoặc số worker cụ thể
pm2 start "npm run start" --name myapp -i 4

Cờ -i max sinh N worker = số CPU core. PM2 dùng Node.js cluster module built-in: master process bind port, fork N child, dùng SO_REUSEPORT chia traffic. App của bạn không cần thay đổi code, miễn là listen trên 0.0.0.0 (hoặc default).

Trên Cloud VPS 50 có 2 core, cluster mode tăng throughput từ ~5000 req/s lên ~9500 req/s cho Express endpoint trả JSON ngắn. Gấp đôi gần như tuyến tính.

Bước 5: Log management và rotate

PM2 tự capture stdout, stderr vào ~/.pm2/logs/{app-name}-out.log và -error.log. Xem realtime:

pm2 logs myapp
pm2 logs myapp --lines 200
pm2 logs --err

Log mặc định không rotate, sau vài tuần có thể 1-2GB. Cài plugin pm2-logrotate:

pm2 install pm2-logrotate
pm2 set pm2-logrotate:max_size 50M
pm2 set pm2-logrotate:retain 7
pm2 set pm2-logrotate:compress true
pm2 set pm2-logrotate:rotateInterval '0 0 * * *'

Cấu hình trên: rotate mỗi ngày 0 giờ, giữ 7 file gần nhất, max 50MB mỗi file, compress file cũ với gzip. Disk usage ổn định không tăng theo thời gian.

Bước 6: ecosystem.config.js cho multi-app

Khi chạy 5-10 app trên cùng VPS, viết command pm2 start dài dòng. Thay bằng file config:

module.exports = {
  apps: [
    {
      name: "api",
      script: "npm",
      args: "run start",
      cwd: "/var/www/api",
      instances: 2,
      exec_mode: "cluster",
      env: { NODE_ENV: "production", PORT: 4000 },
      max_memory_restart: "500M",
      error_file: "/var/log/pm2/api-err.log",
      out_file: "/var/log/pm2/api-out.log",
    },
    {
      name: "web",
      script: "node_modules/.bin/next",
      args: "start -p 3000",
      cwd: "/var/www/web",
      instances: 1,
      exec_mode: "fork",
      env: { NODE_ENV: "production" },
    },
    {
      name: "worker",
      script: "dist/worker.js",
      cwd: "/var/www/worker",
      instances: 1,
      cron_restart: "0 4 * * *",
    },
  ],
};

Start tất cả:

pm2 start ecosystem.config.js
pm2 save

File này commit vào git repo, mỗi deploy chỉ cần pull và pm2 reload ecosystem.config.js.

Bước 7: Zero-downtime reload

cd /var/www/api
git pull
npm install
npm run build
pm2 reload api

Lệnh reload (khác với restart) hoạt động theo rolling: PM2 start worker mới, gửi SIGINT cho worker cũ, đợi nó drain connection rồi kill. User không thấy 502 vì luôn có ít nhất 1 worker phục vụ.

Lưu ý: zero-downtime chỉ work khi cluster mode (instances >= 2). Fork mode bị downtime ngắn 1-3 giây.

Bước 8: max_memory_restart - bảo hiểm memory leak

Node app dễ memory leak (closures, event listener không cleanup, large object trong closure). Đặt max_memory_restart để PM2 tự restart khi vượt ngưỡng:

pm2 start "npm run start" --name myapp 
  --max-memory-restart 500M 
  --restart-delay 5000

Vượt 500MB, PM2 graceful restart. Delay 5 giây giữa các restart để tránh CPU spike. Tính năng này đã cứu nhiều app production trong khi dev chưa fix được nguyên nhân leak.

Bước 9: Monitor real-time

pm2 monit
pm2 status
pm2 info myapp

pm2 monit hiển thị TUI dashboard với CPU, RAM, log realtime của từng app. Đẹp và đủ thông tin cho 90 phần trăm debug daily.

Bước 10: Tích hợp với Caddy/Nginx

PM2 chỉ chạy app. Phía trước cần reverse proxy:

api.your-domain.com {
    reverse_proxy localhost:4000
    encode gzip
}
app.your-domain.com {
    reverse_proxy localhost:3000
    encode gzip
}

Caddy nhận HTTPS, forward về PM2 app trên port nội bộ. User cảm thấy seamless.

Debug khi app crash loop

Restart count tăng nhanh là dấu hiệu loop crash. Các bước debug:

  1. pm2 logs myapp --err --lines 100 xem stack trace.
  2. Tạm stop để tránh CPU 100: pm2 stop myapp.
  3. Chạy app trực tiếp (không qua PM2): node dist/index.js để xem lỗi raw.
  4. Đa số lỗi: missing env var, port đã bị bind, database không connect được, dependency thiếu sau deploy.
  5. Sửa, test, pm2 restart myapp.

PM2 Plus (paid): có đáng không?

PM2 Plus là SaaS thêm dashboard web đẹp, alert email/Slack, custom metric. Giá từ 12 USD/tháng. Đáng khi:

  • Quản lý 10+ app trên nhiều VPS, cần view tập trung.
  • Cần alert khi app crash hoặc memory cao mà không muốn tự build.
  • Team không có DevOps dedicated, cần UI cho non-tech user.

Dev solo có thể thay bằng combo: pm2 monit + Telegram bot script kiểm tra restart count, gửi alert khi tăng bất thường. Tiết kiệm 12 USD/tháng.

Lệnh PM2 cheat sheet

  • pm2 list hoặc pm2 status: xem app đang chạy.
  • pm2 logs [name]: xem log realtime.
  • pm2 restart [name]: restart cứng (downtime ngắn).
  • pm2 reload [name]: reload mềm (zero-downtime, cluster mode).
  • pm2 stop [name]: dừng app.
  • pm2 delete [name]: xóa app khỏi PM2.
  • pm2 save: lưu state để khôi phục sau reboot.
  • pm2 startup: tạo systemd unit.
  • pm2 update: update PM2 binary, restart daemon.
  • pm2 flush: clear toàn bộ log.

So sánh PM2 với systemd

Tiêu chíPM2systemd unit
Setup mỗi app1 lệnhViết unit file, daemon-reload
Cluster modeBuilt-inCần script wrapper
Log rotationPlugin sẵnjournald hoặc logrotate riêng
Zero-downtime reloadKhó, cần dual-port
Memory threshold restart1 cờCần script + cron
Multi-app managementĐơn giảnMỗi app 1 unit file

PM2 cho Node.js, systemd cho Python/Go/Rust binary. Có thể kết hợp: systemd start PM2 daemon (đã tự động qua pm2 startup), PM2 quản các Node app.

FAQ

PM2 có chạy được app Python, Go không?

Có. PM2 chạy bất kỳ executable nào: pm2 start app.py --interpreter python3, pm2 start ./my-go-binary. Nhưng tính năng cluster mode chỉ work với Node.js. Cho Python/Go production, systemd hoặc supervisord phổ biến hơn.

Khi reboot VPS, PM2 có tự start không?

Có nếu bạn đã chạy pm2 startuppm2 save. systemd start PM2 daemon, PM2 đọc dump file (~/.pm2/dump.pm2) và resurrect app đã save. Kiểm tra sau reboot: pm2 status.

PM2 cluster mode có thay được Nginx upstream multi-worker không?

Có cho load balance trong cùng VPS. Nginx upstream phù hợp khi load balance giữa nhiều VPS hoặc cần routing logic phức tạp. PM2 cluster đủ tốt cho single VPS multi-core scenario.

PM2 có an toàn để chạy production thật không?

Có. PM2 đang được dùng trên hàng triệu server toàn cầu, bao gồm Microsoft, IBM, NASA. Cộng đồng lớn, GitHub 41k+ star, update đều. Cài đúng cluster + max_memory_restart + log rotate là yên tâm.

Khi nào nên dùng Docker thay vì PM2?

Khi cần isolation mạnh (mỗi app trong container riêng), khi deploy nhiều VPS qua orchestrator (Kubernetes, Nomad), hoặc khi app phụ thuộc nhiều version Node khác nhau. Dev solo single VPS thường thì PM2 đủ và nhẹ hơn.

Cloud VPS cho vibe coder

Cloud VPS đa core tận dụng tốt nhất với PM2 cluster mode

Cloud VPS TND sẵn AlmaLinux 9, Ubuntu 22/24, Debian 12/13. SSD CEPH, snapshot 1-click, backup hằng ngày, network 200Mbps trong nước. CPU AMD EPYC nhiều core giúp PM2 cluster scale gần tuyến tính, mỗi worker phục vụ tốt traffic Việt Nam dưới 15ms latency.

Xem 8 cấu hình Cloud VPS →

Chia sẻ bài viết