TL;DR
Complete guide to configuring PM2 process management and nginx reverse proxy for production Node.js applications.
Key facts
- Topology
- Node.js + PM2 + nginx
TL;DR
PM2 and nginx form the standard production pair for Node.js on Linux. PM2 manages your Node.js processes with clustering, auto-restarts, and log management, while nginx handles TLS termination, static file serving, and reverse proxying.
PM2 ecosystem configuration
Create ecosystem.config.js in your project root:
module.exports = {
apps: [{
name: 'api',
script: 'dist/server.js',
instances: 'max',
exec_mode: 'cluster',
max_memory_restart: '1G',
node_args: '--max-old-space-size=1536',
env_production: {
NODE_ENV: 'production',
PORT: 3000,
},
error_file: '/var/log/pm2/api-error.log',
out_file: '/var/log/pm2/api-out.log',
merge_logs: true,
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
}],
};
Start with:
pm2 start ecosystem.config.js --env production
PM2 persistence
Ensure processes survive a server reboot:
pm2 startup systemd
pm2 save
PM2 log management
Install the log rotation module to prevent disk fill:
pm2 install pm2-logrotate
pm2 set pm2-logrotate:max_size 50M
pm2 set pm2-logrotate:retain 7
pm2 set pm2-logrotate:compress true
nginx reverse proxy
upstream node_app {
server 127.0.0.1:3000;
keepalive 64;
}
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
gzip on;
gzip_types text/plain application/json application/javascript text/css;
location / {
proxy_pass http://node_app;
proxy_http_version 1.1;
proxy_set_header Connection "";
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;
proxy_read_timeout 60s;
proxy_connect_timeout 10s;
}
location /static/ {
alias /var/www/myapp/public/;
expires 30d;
add_header Cache-Control "public, immutable";
}
}
Test and reload:
sudo nginx -t && sudo systemctl reload nginx
Health checks
Add a health endpoint in your app:
app.get('/health', (req, res) => {
res.json({ status: 'ok', uptime: process.uptime() });
});
Monitor it with PM2's built-in monitoring or configure an external uptime check.
With Reflex
Reflex integrates with both PM2 and nginx to provide unified process monitoring, zero-downtime deployment orchestration, and automated incident response. Instead of SSH-ing in to run pm2 reload and checking nginx logs manually, Reflex handles the full lifecycle with audit trails and rollback capability. See How it works.