PM2 is a production-grade process manager for Node.js applications. Running a Node.js app directly with node server.js has a critical limitation: if the process crashes, it stays down until someone manually restarts it. PM2 solves this and much more — it automatically restarts crashed processes, starts applications on system boot, enables zero-downtime reloads for application updates, manages multiple applications, aggregates logs from all processes, and provides built-in cluster mode that forks the application across all CPU cores to fully utilise multi-core servers. This guide covers deploying a Node.js application with PM2 on RHEL 9, configuring the PM2 ecosystem file, enabling startup on boot, and using cluster mode for horizontal scaling.
Prerequisites
- Node.js installed on RHEL 9
- A Node.js application ready to deploy
Step 1 — Install PM2
npm install -g pm2
pm2 --version
Step 2 — Start an Application with PM2
cd /var/www/myapp
# Start the application
pm2 start server.js --name myapp
# Start with cluster mode (uses all CPU cores)
pm2 start server.js --name myapp --instances max
# Start a TypeScript application
pm2 start npm --name myapp -- start
# View running processes
pm2 list
pm2 show myapp
Step 3 — Create an Ecosystem Configuration File
# ecosystem.config.js — PM2 configuration file
module.exports = {
apps: [
{
name: 'myapp',
script: 'server.js',
instances: 'max', // Use all CPU cores
exec_mode: 'cluster',
watch: false, // Disable in production
max_memory_restart: '512M', // Restart if memory exceeds 512 MB
env: {
NODE_ENV: 'development',
PORT: 3000
},
env_production: {
NODE_ENV: 'production',
PORT: 3000
},
error_file: '/var/log/pm2/myapp-error.log',
out_file: '/var/log/pm2/myapp-out.log',
log_date_format: 'YYYY-MM-DD HH:mm:ss',
merge_logs: true
}
]
};
# Start using the ecosystem file
pm2 start ecosystem.config.js --env production
Step 4 — Enable Startup on Boot
# Generate and configure the startup script
pm2 startup systemd
# PM2 outputs a command to run — execute it, e.g.:
# sudo env PATH=$PATH:/usr/bin pm2 startup systemd -u myuser --hp /home/myuser
# Save the current process list to restore on reboot
pm2 save
# Verify
systemctl status pm2-root # or pm2-
Step 5 — Zero-Downtime Reload and Monitoring
# Zero-downtime reload (cluster mode only — new code loaded without dropping connections)
pm2 reload myapp
# Hard restart (brief downtime)
pm2 restart myapp
# Stop/delete
pm2 stop myapp
pm2 delete myapp
# Real-time monitoring dashboard
pm2 monit
# View logs
pm2 logs myapp --lines 100
# Flush logs
pm2 flush
Step 6 — Nginx Reverse Proxy for PM2 Application
# /etc/nginx/conf.d/myapp.conf
upstream nodeapp {
server 127.0.0.1:3000;
keepalive 64;
}
server {
listen 80;
server_name myapp.example.com;
location / {
proxy_pass http://nodeapp;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
Conclusion
PM2 on RHEL 9 is the production standard for Node.js process management. Cluster mode with instances: 'max' is the single most impactful performance optimisation for CPU-bound Node.js applications — it turns a single-threaded process into a multi-process pool that uses all available CPU cores. Zero-downtime reload (pm2 reload) deploys application updates without dropping any existing connections, making it possible to update Node.js applications without any planned maintenance windows.
Next steps: How to Install Node.js on RHEL 9, How to Install and Configure Nginx on RHEL 9, and How to Monitor Node.js Applications on RHEL 9.