Been running 15 Node.js services on a single 2GB Hetzner VPS ($4.51/month) for about a month now. Wanted to share what I learned about PM2 vs Docker for this use case, since most guides assume Docker.
The Problem
Docker overhead on a 2GB box eats ~600MB before your first container starts. That leaves 1.4GB for actual services. With 15 services, that is ~93MB each — tight enough that OOM kills become routine.
The PM2 Alternative
PM2 overhead: ~30MB total. Leaves 1.97GB for services. Same restart-on-crash behavior, log rotation, monitoring.
What you get:
pm2 start app.js --max-memory-restart 150M — per-process memory limits
pm2 monit — real-time dashboard (free Datadog replacement)
pm2 save && pm2 startup — survives reboots
pm2 logs --lines 100 — aggregated logs
My Actual Stack (725MB total)
| Service |
Memory |
Purpose |
| API server |
112MB |
REST endpoints |
| Nostr relay |
70MB |
WebSocket relay |
| Blog |
34MB |
Static content |
| 5 microservices |
25-45MB each |
Various tools |
| Monitoring |
34MB |
Uptime checks |
| Total |
725MB |
Headroom: 1.27GB |
When Docker Still Wins
- Team environments (image reproducibility matters)
- CI/CD pipelines
- Mixed language stacks (Python + Node + Go)
- When you need network isolation between services
When PM2 Wins
- Solo projects on constrained hardware
- All-Node.js stacks
- When you care about memory more than isolation
- Learning/prototyping (less config overhead)
The key insight: Docker solves organizational problems (reproducible builds, team deployment). PM2 solves resource problems (maximum services per dollar of VPS). Different tools for different constraints.
Anyone else running PM2 in production on small boxes? Curious about other setups.