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

DeluxHost, founded in 2023, offers high-quality hosting solutions for various digital needs. We provide shared hosting, VPS, and dedicated servers with advanced security and global data centers.

© DeluxHost, All rights reserved. | VAT Number : IT17734661006
All Systems Operational