Starting a Node.js app with node server.js works until you close the SSH session, the app crashes, or the server reboots. PM2 is a process manager that keeps apps alive, restarts them on failure, starts them at boot, manages logs and can run one process per CPU core.
Install PM2
PM2 is an npm package. Install it globally (with Node.js already installed — see installing Node.js on Ubuntu):
npm install -g pm2
pm2 -v
With a NodeSource install you’ll need sudo for global packages, or set a user-level npm prefix.
Start an app
cd ~/myapp
pm2 start server.js --name myapp
Other kinds of apps:
pm2 start npm --name web -- start # runs "npm start"
pm2 start "pnpm start" --name web
pm2 start app.py --interpreter python3 # PM2 can supervise non-Node programs too
Everyday commands
| Command | Purpose |
|---|---|
pm2 ls |
List processes with status, CPU, memory, restarts |
pm2 logs myapp |
Stream logs (--lines 200 for history) |
pm2 monit |
Live terminal dashboard |
pm2 show myapp |
Details: paths, env, uptime |
pm2 restart myapp |
Hard restart |
pm2 reload myapp |
Zero-downtime reload (cluster mode) |
pm2 stop myapp |
Stop, keep in the list |
pm2 delete myapp |
Remove from PM2 |
pm2 flush |
Empty log files |
Start on boot
pm2 startup
PM2 prints a command beginning with sudo env PATH=… — copy and run it. It creates a systemd service for your user. Then save the current process list, which is what gets restored at boot:
pm2 save
Run pm2 save again whenever you add or remove apps. After upgrading Node.js, run pm2 update and redo pm2 startup so the service points at the new binary.
The ecosystem file
Command-line flags get unwieldy. Describe apps in ecosystem.config.js and commit it with the code:
module.exports = {
apps: [
{
name: 'myapp',
script: 'server.js',
cwd: '/home/deploy/myapp',
instances: 'max', // one per CPU core
exec_mode: 'cluster',
max_memory_restart: '400M',
env: {
NODE_ENV: 'production',
PORT: 3000,
},
},
{
name: 'worker',
script: 'worker.js',
instances: 1,
cron_restart: '0 4 * * *', // daily restart at 04:00
},
],
};
pm2 start ecosystem.config.js
pm2 reload ecosystem.config.js --update-env
--update-env is required for changed environment variables to take effect — a frequent source of confusion.
Cluster mode
Node runs JavaScript on one thread. In cluster mode PM2 starts several instances and load-balances incoming connections across them, using every CPU core:
pm2 start server.js -i max
Things to know:
- Your app must be stateless between requests: sessions, caches and WebSocket state belong in Redis or a database, not process memory.
pm2 reloadrestarts instances one at a time, so the app stays available during deploys.- On a 1–2 core VPS, cluster mode adds little; the gain comes on 4+ cores.
Logs and rotation
PM2 writes logs to ~/.pm2/logs/<name>-out.log and -error.log. They grow without limit, so install the rotation module:
pm2 install pm2-logrotate
pm2 set pm2-logrotate:max_size 20M
pm2 set pm2-logrotate:retain 10
pm2 set pm2-logrotate:compress true
Memory limits and restarts
max_memory_restart: '400M' restarts an instance that exceeds the limit — a safety net for slow memory leaks, not a fix. Watch the restart counter in pm2 ls; a climbing number means something is wrong. Investigate with pm2 logs and pm2 show.
Deploying updates
A simple deploy script:
cd /home/deploy/myapp
git pull --ff-only
npm ci --omit=dev
npm run build --if-present
pm2 reload ecosystem.config.js --update-env
Put Nginx in front
Bind the app to localhost (HOST=127.0.0.1) and let Nginx terminate HTTPS and serve static files:
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
Full setup: Node.js on a VPS with Nginx.
PM2 or systemd?
systemd is built into Linux and needs no extra software; PM2 adds cluster mode, zero-downtime reloads and friendlier log handling. For a single small service, a systemd unit is enough. For several Node apps, PM2 is more convenient. Either way, avoid running the app as root.
Cluster mode shines with more cores: our KVM VPS plans scale from 1 to 14 vCPU cores, so you can grow without changing your setup.