All posts
vpssizingcostnode.jspythondevopsself-hosting

How Much VPS Do You Actually Need? Sizing CPU, RAM, and Cost for Node and Python Apps

A practical framework for sizing a VPS — how to estimate RAM and CPU from your actual processes, why memory is usually the constraint, and how to measure before you upgrade.

Oxmgr Team ·

How Much VPS Do You Actually Need?

The two failure modes when picking a VPS are equally common: over-buying an 8 GB box for an app that uses 400 MB, or cramming a real workload onto a 512 MB box and getting mysterious OOM kills at 2 a.m. Both come from guessing instead of measuring. Here’s a framework to size it properly.

Memory is almost always the constraint

On modern VPSes, you’ll run out of RAM long before CPU for most web workloads. So size for memory first. Add up what your processes actually use:

ComponentTypical RSS
Node web process60–150 MB each
Python (FastAPI/Django) worker80–200 MB each
JVM app300 MB – 1 GB+
Postgres (small)100–300 MB
Redis (small)20–100 MB
Reverse proxy (Caddy/nginx)10–30 MB
The OS itself150–300 MB
Your process manager~4 MB (Oxmgr) / ~80 MB (PM2)

A concrete example — a Node API with 4 instances, a worker, Postgres, and Caddy:

4 × 120 MB (web)   = 480 MB
1 × 150 MB (worker) = 150 MB
Postgres            = 250 MB
Caddy               =  20 MB
OS                  = 250 MB
process manager     =   4 MB
--------------------------------
Total               ≈ 1.15 GB

Add ~50% headroom for spikes, page cache, and growth → a 2 GB VPS. Not 8. Not 512 MB.

Then check CPU

CPU sizing is about concurrency and per-request work:

  • IO-bound apps (most CRUD APIs — they wait on the database) need surprisingly little CPU. One core handles a lot; you add instances/clustering to use more cores mostly for parallelism and resilience, not because you’re CPU-starved.
  • CPU-bound work (image processing, SSR-heavy pages, WebSocket game state, ML) scales with cores. Here you want instances ≈ cores and you’ll feel the difference.

Rule of thumb: start with 2 vCPU for a small IO-bound app, and only go higher when you’ve measured CPU as the bottleneck.

Measure, don’t guess

The whole point is to replace estimates with numbers from your actual app. Run it under load (even ab/k6 against staging) and watch:

# Per-process memory, live, straight from the process manager
oxmgr ls --json | jq -r '.[] | "(.name)\t(.memory_bytes/1e6|floor)MB\t(.cpu_percent)%"'

# System-wide
free -h        # is memory near full? is swap being touched?
vmstat 1       # 'r' column high = CPU-bound; 'si/so' nonzero = swapping (bad)

Two signals tell you you’re undersized: swap activity (si/so in vmstat — memory is the problem) and a consistently high run queue (r in vmstat above your core count — CPU is the problem). If neither is happening, you have headroom.

The total-footprint jq recipe gives you the exact memory your app stack uses, which is the single most useful number for sizing.

A sizing cheat sheet

WorkloadStart with
Side project, one small app1 GB / 1 vCPU
Small SaaS: app + DB + worker2 GB / 2 vCPU
Busy app, few thousand users4 GB / 2–4 vCPU
CPU-heavy (media, SSR, WS)8 GB / 4+ vCPU
JVM app + DB4 GB minimum (heap eats RAM)

These are starting points to then measure from, not final answers.

Scale up before you scale out

When you do outgrow the box, the cheapest, simplest move is almost always a bigger single box, not a second one. Vertical scaling has no distributed-systems tax — no shared session store, no load balancer, no cross-node database. A single 8 GB VPS runs an enormous amount of app. Only split to multiple servers (or reconsider Kubernetes) when one machine genuinely can’t hold the load or you need failover.

Keep it from creeping

Two habits keep a right-sized box right-sized:

  1. Cap memory per process with resource limits, so a leak recycles a process instead of eating the whole box.
  2. Watch the footprint with a periodic oxmgr ls --json check, so growth is a graph you see coming, not a 2 a.m. page.

Size for memory, verify CPU, measure under load, add headroom, and prefer a bigger box to more boxes. Do that and you’ll neither overpay for idle RAM nor get surprise-killed for lack of it.