Node.js with PM2
PM2 is a process manager for Node.js that keeps the application always running, restarts it automatically after crashes or server reboots, and manages logs.
02
Install Node.js
Recommended method: NodeSource (LTS version)
bash
# Install Node.js 20 LTS (Debian/Ubuntu)
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
apt install -y nodejs
# Verify
node -v
npm -v
bash
# CentOS/AlmaLinux
curl -fsSL https://rpm.nodesource.com/setup_20.x | bash -
dnf install nodejs -y
Manage multiple versions with NVM (optional)
bash
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
source ~/.bashrc
nvm install 20 # Install Node 20
nvm install 18 # Install Node 18
nvm use 20 # Use Node 20
nvm ls # List installed versions
03
Install PM2
bash
npm install -g pm2
04
Start an application with PM2
bash
# Start the app
pm2 start app.js --name "my-app"
# With environment variables
pm2 start app.js --name "my-app" -- --port 3000
# With an ecosystem file (recommended for production, see below)
pm2 start ecosystem.config.js
05
ecosystem.config.js file (advanced configuration)
Create a configuration file in your project folder:
bash
nano /var/www/my-app/ecosystem.config.js
javascript
module.exports = {
apps: [{
name: 'my-app',
script: './app.js', // or 'server.js', 'index.js', etc.
instances: 1, // or 'max' to use all cores
exec_mode: 'fork', // or 'cluster' for multi-core
watch: false, // true for auto-reload on changes (dev only)
max_memory_restart: '500M', // restart if exceeds 500MB RAM
env: {
NODE_ENV: 'production',
PORT: 3000
},
error_file: '/var/log/pm2/my-app-error.log',
out_file: '/var/log/pm2/my-app-out.log',
log_date_format: 'YYYY-MM-DD HH:mm:ss'
}]
};
bash
pm2 start ecosystem.config.js
06
Essential PM2 commands
bash
# List running apps
pm2 list
pm2 status
# Logs in real time
pm2 logs
pm2 logs my-app # Only specific app
pm2 logs --lines 100 # Last 100 lines
# Restart
pm2 restart my-app
# Stop
pm2 stop my-app
# Remove from list
pm2 delete my-app
# Reload without downtime (zero-downtime reload)
pm2 reload my-app
# Real-time monitoring (CPU, RAM, logs)
pm2 monit
07
Automatic startup after server reboot
bash
# Generate and install the startup script
pm2 startup
# Copy and execute the command that PM2 suggests, e.g:
# sudo env PATH=$PATH:/usr/bin pm2 startup systemd -u root --hp /root
# Save the list of active processes
pm2 save
From now on PM2 will automatically restart with all apps after each reboot.
08
Update an app in production
bash
cd /var/www/my-app
git pull origin main
npm install --production
pm2 reload my-app # Zero-downtime if in cluster mode
09
Nginx as reverse proxy for PM2
Expose the app on the internet via Nginx. See the guide: Nginx Reverse Proxy
Quick configuration:
nginx
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
10
Troubleshooting
bash
# Did the app crash?
pm2 list # see status (errored, stopped)
pm2 logs my-app --lines 50 # see why it crashed
# Port already in use
ss -tlnp | grep 3000
# Find and terminate the process using the port
fuser -k 3000/tcp
# App doesn't restart after reboot
pm2 save # Make sure to save the list
pm2 startup # Verify startup is configured
Related articles
