In Part 1, we installed NVM, PM2, configured log rotation, and set up startup scripts. Now let's run the actual application.
Prerequisites
- NVM, Node.js, and PM2 installed (Part 1)
- A Node.js application with a
server.jsorapp.jsentry point - Dependencies installed (
npm installornpm ci)
Start the Application
Single Instance
cd /opt/myapp
pm2 start server.js --name myapp
That's it. PM2 is managing the process.
pm2 status
┌────┬──────┬───────┬───┬─────┬──────────┐
│ id │ name │ mode │ ↺ │ cpu │ memory │
├────┼──────┼───────┼───┼─────┼──────────┤
│ 0 │ myapp│ fork │ 0 │ 0% │ 45.2 MB │
└────┴──────┴───────┴───┴─────┴──────────┘
Cluster Mode — Use All CPU Cores
If your app is stateless (no in-memory sessions), cluster mode spawns one process per CPU core:
pm2 start server.js --name myapp -i max
┌────┬──────┬─────────┬───┬─────┬──────────┐
│ id │ name │ mode │ ↺ │ cpu │ memory │
├────┼──────┼─────────┼───┼─────┼──────────┤
│ 0 │ myapp│ cluster │ 0 │ 0% │ 42.1 MB │
│ 1 │ myapp│ cluster │ 0 │ 0% │ 41.8 MB │
│ 2 │ myapp│ cluster │ 0 │ 0% │ 42.3 MB │
│ 3 │ myapp│ cluster │ 0 │ 0% │ 41.5 MB │
└────┴──────┴─────────┴───┴─────┴──────────┘
Or specify a fixed count:
pm2 start server.js --name myapp -i 2
With Environment Variables
PORT=3000 NODE_ENV=production pm2 start server.js --name myapp -i max
Or pass them explicitly:
pm2 start server.js --name myapp --env production \
--node-args="--max-old-space-size=512" \
-- --port 3000
With a .env File
If your app uses dotenv, just make sure the .env file is in the app's working directory. PM2 runs from the directory where you execute the start command.
cd /opt/myapp
# .env file sits here alongside server.js
pm2 start server.js --name myapp
Memory Limit — Auto Restart on OOM
Set a memory ceiling so a leaky app doesn't eat the whole server:
pm2 start server.js --name myapp --max-memory-restart 512M
When any instance exceeds 512MB, PM2 restarts it automatically.
Watching for File Changes (Dev/Staging Only)
pm2 start server.js --name myapp --watch --ignore-watch="node_modules logs"
Don't use
--watchin production. A deployment that touches multiple files triggers multiple restarts. Usepm2 reloadinstead.
Zero-Downtime Reload
In cluster mode, reload restarts workers one at a time — no dropped requests:
pm2 reload myapp
In fork mode (single instance), reload behaves like restart — there will be a brief downtime.
Verify the Application
# PM2 status
pm2 status
# Port listening?
ss -tlnp | grep 3000
# Hit the app
curl http://localhost:3000
# Logs
pm2 logs myapp --lines 50
Save the Process List
After starting your app, always save:
pm2 save
This writes the current process list to ~/.pm2/dump.pm2. On reboot, the startup script from Part 1 calls pm2 resurrect and restores everything.
Skip pm2 save and your app won't come back after a reboot. Simple as that.
Managing Multiple Applications
PM2 handles multiple apps without issue:
pm2 start /opt/app1/server.js --name api -i 2
pm2 start /opt/app2/app.js --name frontend
pm2 start /opt/app3/worker.js --name worker
pm2 save
┌────┬──────────┬─────────┬───┬─────┬──────────┐
│ id │ name │ mode │ ↺ │ cpu │ memory │
├────┼──────────┼─────────┼───┼─────┼──────────┤
│ 0 │ api │ cluster │ 0 │ 0% │ 42.1 MB │
│ 1 │ api │ cluster │ 0 │ 0% │ 41.8 MB │
│ 2 │ frontend │ fork │ 0 │ 0% │ 38.5 MB │
│ 3 │ worker │ fork │ 0 │ 0% │ 35.2 MB │
└────┴──────────┴─────────┴───┴─────┴──────────┘
Monitoring
Real-Time Dashboard
pm2 monit
Terminal UI showing CPU, memory, logs, and metadata per process.
Quick Health Check
pm2 show myapp
Outputs uptime, restart count, memory usage, log file paths, and more.
Troubleshooting
App crash-looping:
pm2 logs myapp --err --lines 100
Common culprits: missing env vars, port conflicts, unhandled promise rejections.
Port already in use:
sudo lsof -i :3000
PM2 shows errored status:
pm2 describe myapp
High restart_time = crash loop. Check error logs.
What We Have So Far
- ✅ Part 1: NVM + PM2 + startup + log rotation
- ✅ Part 2: App running with PM2, cluster mode, memory limits, zero-downtime reloads
The app is running on localhost:3000 but not exposed to the internet yet.
Top comments (0)