pm2 Process Manager: Keep Your Node.js Bots Running Forever
What You’ll Need
- n8n Cloud or self-hosted n8n (for orchestrating automated workflows)
- Hetzner VPS or Contabo VPS for hosting your Node.js processes
- DigitalOcean as an alternative hosting provider
- Node.js 18+ installed locally and on your server
- SSH access to your VPS
- PM2 (we’ll install this together)
- A text editor (VS Code recommended)
Table of Contents
- Why PM2 Matters for Bot Automation
- Installation & Initial Setup
- Running Your First Process
- Clustering & Load Balancing
- Monitoring & Logs in Real-Time
- Auto-Restart on Server Reboot
- Integration with n8n Webhooks
- Getting Started
Why PM2 Matters for Bot Automation
I learned this the hard way. Three years ago, I deployed a Node.js bot to a VPS—no process manager. It crashed at 2 AM on a Sunday, sat dead for six hours, and tanked the entire automation pipeline. That was the day I discovered PM2.
If you’re running Node.js applications in production—whether it’s a webhook listener for n8n automation, a Telegram bot, a Discord integration, or a custom API server—you need process management. PM2 is the industry standard because it:
- Restarts crashed processes automatically (no manual intervention)
- Clusters your app across CPU cores (load balancing built-in)
- Manages logs (no more digging through syslog)
- Survives server reboots (auto-start on startup)
- Monitors memory and CPU (alerts when things go wrong)
- Handles zero-downtime deployments (reload without dropping connections)
When you’re building automation workflows that depend on external services, uptime isn’t optional. Unlike managed platforms, a VPS doesn’t come with built-in process monitoring. PM2 fills that gap for under $5/month in hosting costs (plus zero subscription fees).
Installation & Initial Setup
SSH into your server and install PM2 globally:
sudo npm install -g pm2
Verify the installation:
pm2 --version
You should see version 5.x or higher. Next, create a directory for your bot project:
mkdir -p ~/projects/automation-bot
cd ~/projects/automation-bot
npm init -y
Install Express and Axios as dependencies (we’ll use these for webhook handling):
npm install express axios dotenv
Now create your first .env file to store configuration:
cat > .env << 'EOF'
PORT=3001
NODE_ENV=production
N8N_WEBHOOK_URL=https://your-n8n-instance.com/webhook/automation
LOG_LEVEL=info
EOF
Running Your First Process
Let me show you a real example. This is a simple Express server that listens for webhooks and triggers actions. Create app.js:
const express = require('express');
const axios = require('axios');
require('dotenv').config();
const app = express();
const PORT = process.env.PORT || 3001;
app.use(express.json());
// Health check endpoint
app.get('/health', (req, res) => {
res.status(200).json({ status: 'ok', timestamp: new Date().toISOString() });
});
// Webhook endpoint
app.post('/webhook/event', async (req, res) => {
try {
const { event_type, data } = req.body;
console.log(`[${new Date().toISOString()}] Received event: ${event_type}`);
// Send to n8n webhook
const response = await axios.post(process.env.N8N_WEBHOOK_URL, {
event_type,
data,
received_at: new Date().toISOString(),
server_hostname: require('os').hostname()
});
res.status(200).json({
success: true,
message: 'Event processed',
n8n_response: response.status
});
} catch (error) {
console.error(`[ERROR] ${error.message}`);
res.status(500).json({
success: false,
error: error.message
});
}
});
// Error handling middleware
app.use((err, req, res, next) => {
console.error('Unhandled error:', err);
res.status(500).json({ error: 'Internal server error' });
});
app.listen(PORT, () => {
console.log(`[${new Date().toISOString()}] Server running on port ${PORT}`);
console.log(`Health check: http://localhost:${PORT}/health`);
});
// Graceful shutdown
process.on('SIGTERM', () => {
console.log('SIGTERM received, shutting down gracefully');
process.exit(0);
});
Now start this with PM2:
pm2 start app.js --name "webhook-bot"
Check the status:
pm2 status
You’ll see output like:
┌─────┬──────────────┬─────────────┬──────┬────────┬──────────┐
│ id │ name │ namespace │ mode │ status │ restart │
├─────┼──────────────┼─────────────┼──────┼────────┼──────────┤
│ 0 │ webhook-bot │ default │ fork │ online │ 0 │
└─────┴──────────────┴─────────────┴──────┴────────┴──────────┘
Test it:
curl -X POST http://localhost:3001/webhook/event \
-H "Content-Type: application/json" \
-d '{"event_type":"test","data":{"message":"hello"}}'
💡 Fast-Track Your Project: Don’t want to configure this yourself? I build custom n8n pipelines and bots. Message me with code SYS3-HUGO.
Clustering & Load Balancing
Here’s where PM2 gets powerful. Instead of running a single process, you can spawn one worker per CPU core. This means if your server has 4 cores, PM2 will automatically load-balance across 4 instances of your app.
Create an ecosystem.config.js file in your project root:
module.exports = {
apps: [
{
name: 'webhook-bot',
script: './app.js',
instances: 'max',
exec_mode: 'cluster',
env: {
NODE_ENV: 'production',
PORT: 3001
},
merge_logs: true,
autorestart: true,
watch: false,
max_memory_restart: '500M',
error_file: './logs/err.log',
out_file: './logs/out.log',
log_date_format: 'YYYY-MM-DD HH:mm:ss Z'
}
]
};
Stop the current process and restart using this config:
pm2 stop webhook-bot
pm2 start ecosystem.config.js
Check the cluster:
pm2 status
Now you’ll see multiple instances (one per core):
┌─────┬──────────────┬─────────────┬──────────┬────────┬──────────┐
│ id │ name │ namespace │ mode │ status │ restart │
├─────┼──────────────┼─────────────┼──────────┼────────┼──────────┤
│ 0 │ webhook-bot │ default │ cluster │ online │ 0 │
│ 1 │ webhook-bot │ default │ cluster │ online │ 0 │
│ 2 │ webhook-bot │ default │ cluster │ online │ 0 │
│ 3 │ webhook-bot │ default │ cluster │ online │ 0 │
└─────┴──────────────┴─────────────┴──────────┴──────────┴──────────┘
This is key for production. If one instance crashes, PM2 auto-restarts it while the others keep handling requests. When you’re comparing automation platforms—whether it’s n8n vs Make vs Zapier —self-hosted solutions like n8n running on your own VPS require this kind of reliability layer.
Monitoring & Logs in Real-Time
Watch all your processes in a dashboard:
pm2 monit
This shows CPU, memory, requests per minute, and restart counts. Press q to exit.
View logs for a specific app:
pm2 logs webhook-bot
Or tail the last 100 lines:
pm2 logs webhook-bot --lines 100
For a broader view of what’s happening, save all logs to files. The ecosystem.config.js I provided earlier already does this. Check your logs:
tail -f ~/projects/automation-bot/logs/out.log
You can also rotate logs automatically. Install the PM2 logrotate module:
pm2 install pm2-logrotate
Configure it to keep logs under 10MB:
pm2 set pm2-logrotate:max_size 10M
pm2 set pm2-logrotate:retain 7
This keeps your disk clean—critical when you’re running high-volume webhook receivers on a budget VPS like Hetzner or Contabo .
Auto-Restart on Server Reboot
If your VPS restarts (whether planned or due to a crash), PM2 needs to resurrect your processes. We do this by creating a startup script:
pm2 startup
This command outputs a line you need to run. It looks like:
sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u ubuntu --hp /home/ubuntu
Copy and run that exact line. Then save your current process list:
pm2 save
Now test it. Reboot your server:
sudo reboot
Wait 30 seconds, SSH back in, and check:
pm2 status
Your processes should be running. If they’re not, check the systemd service:
systemctl status pm2-ubuntu
Integration with n8n Webhooks
This is where it gets practical. When you’re running a self-hosted n8n instance, you often need a separate Node.js service to handle incoming webhooks and trigger workflows. PM2 keeps that service alive.
Here’s a real workflow: your PM2-managed bot listens on port 3001, receives events, and hits your n8n webhook to trigger an automation.
Modify your .env:
cat > .env << 'EOF'
PORT=3001
NODE_ENV=production
N8N_WEBHOOK_URL=https://your-n8n-domain.com/webhook/
Want to automate this yourself?
Start with n8n Cloud (free tier available) or self-host on a Hetzner VPS for full control.
📬 Get Weekly Automation Tips
One email per week with tutorials, tools, and workflows. No spam, unsubscribe anytime.