Cài đặt Node.js và PM2 trên CentOS Stream 9: Bí kíp để ứng dụng không bao giờ “sập” lúc 2 giờ sáng

CentOS tutorial - IT technology blog
CentOS tutorial - IT technology blog

Cơn ác mộng 502 Bad Gateway và bài học từ thực tế

Điện thoại mình rung bần bật lúc 2 giờ sáng. Đầu dây bên kia là tiếng sếp gắt gỏng: “Web sập rồi em ơi, khách đang checkout thì lỗi 502”. Mình lật đật bật máy, SSH vào con server CentOS Stream 9. Gõ ps aux | grep node thì kết quả trống trơn.

Vấn đề rất sơ đẳng: Tối qua mình chạy npm start rồi tắt terminal đi ngủ. Khi session SSH kết thúc, CentOS sẽ tự động quét và dọn dẹp các tiến trình con. Kết quả là ứng dụng “bay màu” ngay lập tức. Hoặc chỉ cần một lỗi uncaughtException nhỏ, Node.js sẽ crash và nằm im chờ người đến cứu.

Sau đợt chuyển đổi 5 server từ CentOS 8 sang CentOS Stream 9, mình nhận ra: Muốn ngủ ngon, tuyệt đối không chạy Node.js trực tiếp trên production. Bạn cần một bộ quản lý tiến trình (Process Manager) đủ tin cậy. Đó là lý do PM2 xuất hiện.

Tại sao ứng dụng Node.js của bạn thường xuyên biến mất?

Node.js vận hành trên cơ chế single-thread. Chỉ cần một lỗi logic không được handle, toàn bộ process sẽ dừng lại. Trên môi trường dev, bạn có thể chạy lại lệnh thủ công. Nhưng trên production, bạn không thể ngồi canh server 24/7.

Dưới đây là 4 “hung thần” thường xuyên giết chết app Node.js trên CentOS:

  • Session Timeout: Tắt cửa sổ terminal đồng nghĩa với việc khai tử process.
  • Lỗi Runtime: Code lỗi khiến process crash bất thình lình.
  • Server Reboot: Nhà cung cấp Cloud bảo trì hoặc update kernel khiến server khởi động lại.
  • OOM (Out of Memory): Trên các VPS RAM thấp (ví dụ bản 1GB), app ngốn quá nhiều tài nguyên sẽ bị hệ thống kill để bảo vệ OS.

PM2: Giải pháp chuyên nghiệp thay thế cho nohup và Systemd

Nhiều bạn mới thường dùng nohup node app.js &. Cách này giúp app không chết khi tắt terminal nhưng lại cực kỳ khó quản lý log. Một số người dùng Systemd để tạo file .service. Cách này chuẩn Linux nhưng mỗi lần thêm app mới lại phải cấu hình file rất rườm rà.

PM2 (Process Manager 2) là lựa chọn tối ưu hơn cả. Nó cung cấp đầy đủ: Tự động restart khi crash, quản lý log tập trung và theo dõi tài nguyên thời gian thực chỉ bằng vài câu lệnh đơn giản.

Cài đặt Node.js trên CentOS Stream 9: Chọn bản LTS để ổn định

CentOS Stream 9 quản lý phần mềm qua AppStream. Thay vì cài bản cũ trong repo mặc định, hãy chọn bản Long Term Support (LTS) để đảm bảo các thư viện chạy mượt mà nhất.

Bước 1: Kiểm tra các phiên bản Node.js khả dụng

sudo dnf module list nodejs

Hệ thống sẽ liệt kê các stream như 16, 18, 20. Mình khuyên bạn nên chọn Node.js 20. Đây là bản LTS hiện đại, hỗ trợ tốt nhất cho các framework như Next.js hay NestJS.

Bước 2: Kích hoạt và cài đặt

# Chọn stream phiên bản 20
sudo dnf module enable nodejs:20 -y

# Cài đặt nodejs và npm
sudo dnf install nodejs -y

# Xác nhận phiên bản
node -v

PM2 – “Vệ sĩ” tận tụy cho ứng dụng của bạn

Sau khi có Node.js, hãy cài PM2 toàn cục (global) để điều khiển hệ thống từ bất cứ đâu.

sudo npm install pm2 -g

Khởi chạy ứng dụng đầu tiên

Giả sử dự án của bạn nằm tại /var/www/api-service/index.js. Thay vì dùng lệnh node thông thường, hãy để PM2 tiếp quản:

cd /var/www/api-service
pm2 start index.js --name "api-production"

Lúc này, app của bạn đã an toàn. Dù bạn log out SSH, ứng dụng vẫn âm thầm phục vụ người dùng.

Lệnh điều khiển nhanh khi cần troubleshoot

Trong quá trình vận hành, mình thường dùng các lệnh sau để xử lý sự cố:

  • pm2 list: Kiểm tra xem app đang ngốn bao nhiêu RAM và CPU.
  • pm2 logs api-production: Xem log trực tiếp. Rất hữu ích khi cần tìm nguyên nhân gây lỗi 500.
  • pm2 restart api-production: Khởi động lại app sau khi bạn vừa cập nhật code mới.

Cấu hình tự khởi động cùng hệ thống

Đây là bước quan trọng nhất mà nhiều người bỏ qua. Nếu server bị reboot, PM2 sẽ không tự chạy lại trừ khi bạn thiết lập Startup Script.

Đầu tiên, hãy yêu cầu PM2 tạo lệnh startup cho systemd:

pm2 startup

Hệ thống sẽ trả về một dòng lệnh dài bắt đầu bằng sudo env PATH=.... Bạn cần copy toàn bộ dòng đó, dán vào terminal và nhấn Enter.

Cuối cùng, lưu trạng thái hiện tại để PM2 ghi nhớ các app đang chạy:

pm2 save

Bây giờ, bạn có thể thử sudo reboot. Khi server khởi động xong, app của bạn sẽ tự động “hồi sinh” mà không cần tác động thủ công.

Mở port Firewall trên CentOS Stream 9

Nếu app chạy port 3000 nhưng trình duyệt không truy cập được, khả năng cao firewalld đang chặn đường. Hãy mở port bằng lệnh:

sudo firewall-cmd --permanent --add-port=3000/tcp
sudo firewall-cmd --reload

Mẹo nâng cao: Tận dụng Cluster Mode

Node.js mặc định chỉ chạy trên 1 nhân CPU. Nếu server của bạn có 4 nhân, bạn đang lãng phí 75% sức mạnh phần cứng. PM2 có tính năng Cluster Mode giúp chạy nhiều instance cùng lúc:

# Tận dụng tối đa số nhân CPU hiện có
pm2 start index.js -i max

Với cấu hình này, nếu một instance bị crash, các instance khác vẫn xử lý request bình thường. Điều này giúp hệ thống đạt mức downtime gần như bằng không (Zero Downtime).

Việc quản lý Node.js trên CentOS Stream 9 sẽ trở nên cực kỳ nhàn nhã nếu bạn thiết lập đúng quy trình ngay từ đầu. Hy vọng những kinh nghiệm thực chiến này giúp hệ thống của bạn luôn vững vàng trước mọi đợt traffic lớn.

Share: