How Much RAM Does Your VPS Need? Estimate It, Then Measure

Published on

Size VPS RAM from what your OS, database, PHP, Node.js, Docker and game server document, then check real use with free, htop, docker stats and the OOM log.

Screenshot of a VPS dashboard with a disk usage bar at 0.96 of 120 GB and a bandwidth meter at 0 percent in and out

You are choosing a VPS plan, or the one you have keeps losing processes without an error, and every RAM table online gives a different number for the same software. Most of those tables are guesses. The software you run documents how it uses memory, and Linux shows what is in use now. This guide turns both into a number: estimate, measure, leave headroom, add a little swap, and know the signs that you are short. Commands are for Ubuntu 24.04 and Debian 12.

Quick answer: Add up the operating system and what each program is allowed to use: the database cache, PHP or app workers times the size of one, the Node.js or Java heap limit, and every container. Pick a plan where that total stays under about three quarters of the RAM, the ratio the Node.js docs use in their own example. Then run free -h at your busiest hour: available is what is really left. If it nears zero, vmstat shows steady swapping, or the kernel log says Out of memory: Killed process, lower those limits or add RAM.

Step 1: Add Up What Each Program Documents

Debian's installation guide puts it plainly: "It is practically impossible to give general memory or disk space requirements for server installations as those very much depend on what the server is to be used for." So build it from the parts:

PartWhat its RAM depends onWhat its docs say
Ubuntu Server 24.04The base system1 GB minimum for cloud images, 1.5 GB for ISO installs; 3 GB or more suggested for complex setups
Debian 12The base systemWithout a desktop: 256 MB minimum (with swap enabled), 512 MB recommended
nginxOpen connections"10,000 inactive HTTP keep-alive connections take about 2.5M memory"
PHP-FPMpm.max_children times one workerThe pool file PHP ships sets pm.max_children = 5, the limit on simultaneous requests
MariaDBinnodb_buffer_pool_size128 MiB by default; up to 80% of RAM on a database server with mostly InnoDB tables
PostgreSQLshared_buffers, plus work_mem per sort or hash128 MB and 4 MB by default; 25% of RAM as a start on a dedicated database server
DockerEvery container"By default, a container has no resource constraints"
Node.jsThe V8 heap, --max-old-space-size1536 MiB on a 2 GiB machine "to leave some memory for other uses and avoid swapping"
n8nJSON and binary data per execution, Code nodes, parallel workflows"n8n doesn't restrict the amount of data each node can fetch and process"
Minecraft (Paper)The Java heap (-Xmx) plus JVM overheadAt least 6 to 10 GB; set -Xmx about 1000 to 1500 MB below the RAM you have

Three things in that table decide most sizes.

Database caches are the big lever. The 128 MB defaults fit almost anywhere (Debian 12's MariaDB config keeps the default). The 80% (MariaDB) and 25% (PostgreSQL) figures are for servers that run only the database; on a VPS that also runs your app, size the cache from what is left. PostgreSQL adds a warning about work_mem: one query can run several sorts at once and "several running sessions could be doing such operations concurrently", so the total "could be many times the value of work_mem". MariaDB warns against a pool so large that it "can cause swapping".

Workers multiply. A PHP-FPM pool uses pm.max_children times the size of one busy worker, and Apache's prefork workers add up the same way. Apache's tuning guide gives the method: find "the size of your average Apache process" in top "and divide this into your total available memory, leaving some room for other processes". On Debian 12 (PHP 8.2) and Ubuntu 24.04 (PHP 8.3) the pool file is /etc/php/<version>/fpm/pool.d/www.conf:

grep -E '^pm' /etc/php/*/fpm/pool.d/www.conf

Heaps have limits, processes need more. Node.js and Java can grow their heap up to the limit you set, but the process uses memory beyond the heap. In Java 21, class metadata lives outside it, and for that space "By default, the size isn't limited." Without -Xmx, Java's maximum heap defaults to 25 percent of the memory available to it (MaxRAMPercentage). Per workload, see our guides to Minecraft server RAM, Discord bot RAM and n8n system requirements.

Step 2: Measure What the Server Uses Now

On a server that already runs, measure during the busiest hour of the week (backups, cron batches, peak players), not right after a reboot.

free: How Much Is Really Left

free -h

The columns are total, used, free, shared, buff/cache and available:

  • available is the one to watch: an "Estimation of how much memory is available for starting new applications, without swapping."
  • used is total minus available, on both Ubuntu 24.04 and Debian 12.
  • free is memory nothing uses. It is low on a healthy server: Linux fills spare RAM with page cache (buff/cache) and gives it back on demand.

htop and ps: Which Process Uses It

sudo apt install htop   # if it is missing
htop

Press M to sort by memory, H to toggle user threads (when shown, each thread gets its own line) and F4 to filter by name, such as php-fpm. Read RES, "the size of the process's used physical memory", not the virtual size VIRT. RES counts shared pages in every process that maps them, so a sum over many workers runs high; the PSS column (add it in the F2 setup screen) splits shared pages between the processes.

For a list you can paste into a ticket (RSS is in kilobytes):

ps -eo pid,rss,comm --sort=-rss | head -n 15

docker stats: Memory per Container

sudo docker stats --no-stream

MEM USAGE / LIMIT shows "the total memory the container is using, and the total amount of memory it is allowed to use", and on Linux the CLI subtracts cache from that figure. A container without a limit can use the whole VPS, and Docker warns that when memory runs out the kernel may kill any process, "including Docker and other important applications". So give each container a limit: --memory=1g on docker run, or in Compose:

services:
  app:
    mem_limit: 1g

vmstat: Is It Swapping Right Now

vmstat 5

Skip the first line: it gives "averages since the last reboot". After that, si and so are the memory swapped in from disk and out to disk per second. Zeros, or a short burst during a backup, are fine. Non-zero values in most lines while the server is busy mean your programs no longer fit in RAM.

Step 3: Leave Headroom

Three of the sources above build in a margin: the Node.js example leaves a quarter of a 2 GiB machine "for other uses", PaperMC takes 1000 to 1500 MB off for the JVM and the operating system, and Apache leaves "some room for other processes". Unused RAM isn't wasted either. Linux uses it as page cache, and PostgreSQL counts on that: because it "also relies on the operating system cache", its docs doubt that more than 40% of RAM for shared_buffers beats a smaller setting.

A workable rule: keep your estimate, or the peak used you measured, under about three quarters of the RAM. If your services add up to 3 GB, 4 GB is the floor, and 8 GB gives the database room to cache more.

On a Space-Node VPS the RAM in your plan is dedicated to your KVM server (see guaranteed vs burstable RAM), and the plans run from 2 GB to 48 GB.

Step 4: Add Swap as a Buffer, Not as RAM

Docker's docs put it well: "Swap is slower than memory but can provide a buffer against running out of system memory." It catches a rare peak so the kernel doesn't have to kill anything. It is not extra RAM, and Apache's guide says a web server "should never ever have to swap".

Check what you have:

swapon --show
free -h

If swapon --show lists nothing and the Swap line of free -h shows a total of 0, there is no swap. To add a 2 GiB swap file:

sudo dd if=/dev/zero of=/swapfile bs=1MiB count=2048
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap defaults 0 0' | sudo tee -a /etc/fstab

The swapon man page calls dd with /dev/zero "The most portable solution to create a swap file", because swapon rejects files with holes. chmod 600 matters, since swapon warns when other users can access the file. The /etc/fstab line brings the swap back after a reboot. On a Btrfs root filesystem, read the swapon(8) notes first.

vm.swappiness (default 60, range 0 to 200) weighs swapping against dropping page cache. The kernel docs say the best value "will require experimentation and will also be workload-dependent", so leave it until you have measured a problem. One Docker detail: with swap on the host, a container that has --memory but no --memory-swap "can use as much swap as the --memory setting", so a 1g limit means 1g of RAM plus up to 1g of swap.

Signs Your VPS Is Short of RAM

The kernel's OOM killer. When memory runs out, the kernel kills a process and logs it:

sudo journalctl -k | grep -i -E 'out of memory|killed process'
sudo journalctl -k -b -1 | grep -i 'killed process'

-k covers the current boot; the second line checks the one before, if your journal kept it (journalctl --list-boots lists them). A message Out of memory: Killed process ... means the whole VPS ran out. Memory cgroup out of memory: Killed process ... means a memory limit was hit, such as a container's --memory: raise that limit or trim that service.

A systemd service stopped. Its log, journalctl -u <service>, shows "A process of this unit has been killed by the OOM killer." Under the default OOMPolicy=stop, systemd then stops the unit, which ends with Failed with result 'oom-kill'.

A container was killed. sudo docker inspect --format '{{.State.OOMKilled}}' <container> prints true if a process in it "has been killed because it ran out of memory since the container was last started". Exit code 137 is 128 plus 9: Bash reports a command killed by a signal as 128 plus the signal's number, and the OOM killer sends SIGKILL, signal 9. Our exit code 137 guide covers game servers.

A heap error while RAM is free. JavaScript heap out of memory (Node.js apps such as n8n) and java.lang.OutOfMemoryError with the detail Java heap space mean the heap filled up: its limit is too small for the work, or something leaks. That is not the same as a full VPS. Oracle notes the cause "can be as simple as a configuration issue". If free -h still shows plenty available, raise --max-old-space-size (for n8n through NODE_OPTIONS) or -Xmx.

Steady swapping. si and so busy in vmstat, and available near zero at your peak.

Fix it in this order: find the process with htop or ps, lower its workers, cache or heap if they exceed what the server has, set container limits, keep a swap file as a buffer, and only then add RAM. A process that keeps growing until it is killed, however much you give it, is leaking; more RAM only delays the next kill. On Space-Node you move to a bigger plan from the client area.

FAQ

Is 1 GB of RAM enough for a VPS? For the base system, yes: Debian recommends 512 MB without a desktop, and Ubuntu lists 1 GB as the minimum for cloud images. Each database, PHP pool or container adds its own share on top (step 1), and Ubuntu suggests 3 GB or more for complex setups.

Why does free show almost no free memory? Because Linux uses unused RAM as page cache. It shows under buff/cache and goes back to programs on demand. Watch available, which accounts for the cache.

Why does free show less RAM than my plan has? The total column leaves out "a few reserved bits and kernel binary code", and free -h prints binary units (Gi), so the figure comes out a little below the plan's.

Can swap replace RAM? No. Swap lives on disk and is slower than memory. Use it as a buffer for rare peaks; if si and so are busy every day, you need more RAM.

Should I give my Minecraft server all of the VPS's RAM? No. PaperMC says not to use the full 8 GB on an 8 GB host and suggests 6500 MB, because Java needs memory on top of -Xmx and the operating system needs some too. You can also run it on Minecraft hosting instead of a VPS.

Sources

All opened on 30 October 2026: