PM2 Cluster Mode on a VPS: ecosystem.config.js for 1–4GB Nodes (2026)

Published · Updated

PM2 Cluster Mode on a VPS: ecosystem.config.js for 1–4GB Nodes (2026)

Running Node.js in production on a budget VPS (like a $5 Hetzner or DigitalOcean node) requires careful resource management. By default, Node.js runs as a single process on a single CPU core. To truly leverage your VPS hardware and ensure 99.9% uptime, you need PM2 Cluster Mode.

In this guide, we’ll configure PM2 for maximum performance while keeping your footprint small enough for “cheap” VPS tiers. After tuning PM2, use this Zero-Downtime Node.js deployment workflow to ship changes without visible downtime.

OptimizationRecommended ValueWhy?
Instances'max'Use all CPU cores for throughput
Exec Mode'cluster'Load balance without code changes
Max RAM800MPrevent memory leaks from freezing VPS
Log Rotationpm2-logrotateAvoid disk bloat on 20GB nodes
Node Versionv25+Better RAM management & V8 optimizations

Why Cluster Mode?

A single Node.js instance cannot utilize multiple CPU cores. If your VPS has 2 or more vCPUs (like the Hetzner CX22), a single node app.js process leaves 50% of your compute power idle.

Cluster Mode allows PM2 to spawn multiple “workers” that share the same port, effectively load-balancing traffic across all available CPU cores without changing a single line of your code.

PM2 Cluster Mode Dashboard showing multiple Node.js instances active


The Production Config: ecosystem.config.js

Instead of running PM2 commands manually, always use an ecosystem file. This ensures your settings are version-controlled and consistent.

Create ecosystem.config.js in your project root:

module.exports = {
  apps: [{
    name: 'nodejs-vps-app',
    script: './dist/index.js',
    // Options for High Performance
    instances: 'max',       // Spawns one worker per CPU core
    exec_mode: 'cluster',   // Enables the cluster module
    
    // RAM Management (Critical for Cheap VPS)
    max_memory_restart: '800M', // Restarts worker if it exceeds 800MB
    
    // Recovery & Uptime
    autorestart: true,
    watch: false,           // Set to false in production
    max_restarts: 10,
    restart_delay: 4000,    // Wait 4s before restarting a crashed app
    
    // Environment Variables
    env_production: {
      NODE_ENV: 'production',
      PORT: 3000
    }
  }]
};

Why max_memory_restart matters

On a VPS with only 1GB or 2GB of RAM, a single memory leak can freeze the entire OS. By setting a limit (e.g., 800M), PM2 will gracefully kill and restart a worker before it crashes the server.


Zero-Downtime Deploys

One of the biggest benefits of PM2 is the ability to update your app without dropping a single request.

Instead of pm2 restart, use:

pm2 reload ecosystem.config.js

How it works: PM2 restarts workers one by one. It waits for a new worker to be “online” before killing the old one. If your app is in Cluster Mode, your users will never see a 502 error during a deploy.


Monitoring and Log Management

1. Real-time Dashboard

Run pm2 monit on your server to see a real-time terminal dashboard of CPU and RAM usage per worker. If you see one worker constantly hitting 100% CPU, it’s time to scale your VPS or optimize your event loop.

2. Avoiding Disk Bloat

Logs can quickly fill up a small 20GB VPS disk. Install the logrotate module immediately:

pm2 install pm2-logrotate

This automatically compresses and rotates your logs, keeping only the last few MBs.


How Many Node.js Apps Can I Deploy on a 2-Core 1GB VPS with PM2?

This is the most common question for developers on entry-tier cloud nodes (Hetzner CX11, DigitalOcean Basic 1GB, Vultr Cloud Compute 1GB). The short answer: 2–3 small apps, or 1 app in full cluster mode. Here’s the math.

Memory Budget on a 1GB VPS

The OS and PM2 daemon consume RAM before your app even starts:

ComponentRAM Used
Ubuntu 22.04 (minimal)~180MB
PM2 daemon~30MB
Available for apps~790MB

That 790MB is what you actually have. From there:

App TypeIdle RAMUnder LoadMax Apps (2-core 1GB)
Simple bot / webhook60–90MB~120MB6–8 apps (fork mode)
Standard REST API (Express/Fastify)80–120MB~200MB2–3 apps
Next.js / Nuxt SSR350–500MB600MB+1 app only
Heavy AI / Discord bot600MB+OOM risk1 app + swap

Option A: One App, Full Cluster Mode (2 workers)

Use this when you have a single API that needs to use both CPU cores:

module.exports = {
  apps: [{
    name: 'my-api',
    script: './dist/index.js',
    instances: 2,          // exactly 2 workers for 2-core VPS
    exec_mode: 'cluster',
    max_memory_restart: '350M', // restart worker before it eats all RAM
    node_args: '--max-old-space-size=320',
    env_production: { NODE_ENV: 'production', PORT: 3000 }
  }]
};

With 2 workers × 350MB limit = 700MB max, leaving ~90MB headroom for the OS.

Option B: Multiple Small Apps, Fork Mode

Use this when you’re hosting 2–3 separate projects on the same VPS:

module.exports = {
  apps: [
    {
      name: 'api',
      script: './api/dist/index.js',
      instances: 1,
      exec_mode: 'fork',
      max_memory_restart: '250M',
      node_args: '--max-old-space-size=200',
    },
    {
      name: 'worker',
      script: './worker/dist/index.js',
      instances: 1,
      exec_mode: 'fork',
      max_memory_restart: '200M',
      node_args: '--max-old-space-size=160',
    }
  ]
};

Two apps × ~200MB = 400MB used, leaving ~390MB free for spikes.

Pro Tips for 2-Core 1GB Nodes

  • Always add a swap file: fallocate -l 2G /swapfile && mkswap /swapfile && swapon /swapfile. On a 1GB VPS this is not optional — it absorbs deployment spikes that would otherwise OOM-kill your app.
  • Use node_args: '--max-old-space-size=N' to cap V8 heap. Without it, Node.js may claim up to 1.5GB and crash the server.
  • Monitor with pm2 monit: If a worker is consistently near its max_memory_restart limit, your app has a memory leak — fix the code rather than raising the limit.

Best Practices for Budget VPS

  1. Node.js v25+: Use the latest LTS or stable version. Modern V8 engines have significantly better memory pointer compression, saving up to 20% RAM out of the box.
  2. Graceful Shutdown: In your code, listen for the SIGINT signal to close database connections before PM2 kills the process:
    process.on('SIGINT', () => {
      server.close(() => {
        db.disconnect();
        process.exit(0);
      });
    });
  3. Swap File: On a 1GB VPS, always create a 2GB swap file. It acts as a safety net for temporary RAM spikes.

Conclusion

PM2 is more than just a process manager; it’s a production-grade load balancer for your VPS. By using Cluster Mode and Memory Restarts, you can run high-traffic applications on surprisingly cheap hardware.

Next Step: Learn how to put Nginx in front of PM2 for SSL and caching in our Complete Hosting Guide.
Then implement full CI/CD rollout with health checks and fast rollback in Zero-Downtime Node.js Deployment on VPS.