You’re sizing a homelab box and the RAM question is the one that actually decides what you can run. So how much RAM for Proxmox do you actually need? CPU cores matter, storage matters, but RAM is the wall you hit first. Spin up one VM too many on a 16GB node and the OOM killer starts reaping processes, or worse, swap thrashing drags the whole host to a crawl. I have watched it happen on my own cluster more than once.
This guide breaks down where RAM goes on a Proxmox VE host: the hypervisor base, each VM and LXC container, the ZFS ARC cache (the single biggest surprise for newcomers), plus KSM, ballooning, and the headroom you need for backups and live migration. Then a tier table for 16GB, 32GB, 64GB, and 128GB so you can match the box to the workload. The numbers come off two Proxmox nodes I run, measured in June with most guests off and again in October with 18 running.
Re-measured in October 2026 on the same two Proxmox VE 8.4 nodes, this time with the lab busy.
Start with the Proxmox host base
Proxmox VE itself is lean. The kernel, the management daemons (pveproxy, pvedaemon, pvestatd), the web UI, and the cluster stack together idle at roughly 1.5 to 2GB. That is your floor before a single guest boots.
In June I checked one of my nodes with the hypervisor running and one light VM (a single Ubuntu guest) booted:
free -h
On a 64GB node, used memory sat around 7GB with just the host and one VM. About 3.3GiB of that was the ZFS ARC, which free counts as used, roughly 2GiB was Proxmox itself, and the guest was the rest:
total used free shared buff/cache available
Mem: 62Gi 7.1Gi 53Gi 65Mi 2.8Gi 55Gi
Swap: 8.0Gi 0B 8.0Gi
Two things to read off that. First, 64GB of RAM shows as 62GiB. The DIMMs really are 64GiB; the missing 1.3GiB is memory the kernel never reports in MemTotal, mostly about 1GiB for its own page-tracking structures plus the kernel image, with only around 117MiB kept by the firmware on pve01. Never plan to use the full nameplate number. Second, swap is present (an 8GB LVM volume the installer created on these XFS-root nodes) but completely unused, which is exactly what you want. A homelab host that is dipping into swap under normal load is a host that needs more RAM, not a bigger swap file.
To see what the Proxmox services themselves hold, add up the resident memory of each daemon. This one-liner groups ps output by process name and prints MiB:
ps -eo rss,comm | awk '/pve|corosync|pmxcfs|spiceproxy|qmeventd/{a[$2]+=$1} END{for(k in a) printf "%s %d\n",k,a[k]/1024}' | sort
On pve01 in October it printed the following, with four VMs running on the node:
corosync 163
pmxcfs 68
pvedaemon 575
pve-firewall 104
pvefw-logger 2
pve-ha-crm 117
pve-ha-lrm 116
pve-lxc-syscall 3
pveproxy 624
pvescheduler 118
pvestatd 118
qmeventd 1
spiceproxy 119
The total is about 2.1 GiB, and two processes carry most of it: pveproxy (624 MiB) serves the web UI and API, and pvedaemon (575 MiB) does the privileged work behind it. Both run several worker processes that share most of their Perl code, and RSS counts a shared page once per process, so the real cost is lower than the sum. That is where the 1.5 to 2GB floor comes from, and it does not grow with the number of guests: pve02, running fourteen VMs, showed nearly the same figures. Only pvestatd, which polls every guest for its status, grew, from 118 to 149 MiB.
Size each VM and LXC container
Every full VM carries the weight of its own guest kernel and userland on top of whatever the workload needs. Inside the guest, a bare Linux VM idles around 0.5 to 1GB. Give it a database, a web app, or a Kubernetes node and that climbs fast. A Windows Server guest wants 4GB before it does anything useful.
LXC containers are the cheat code here. A container shares the host kernel, so it skips the whole guest-OS overhead. The same workload that needs a 2GB VM often runs comfortably in a 512MB to 1GB LXC. Plenty of homelabbers default everything to a VM out of habit and then wonder where their RAM went. If the workload is Linux and you do not specifically need kernel isolation or a different kernel version, reach for an LXC first.
We measured the gap on the same cluster in October, because the host side of a VM is where the surprise is. An Ubuntu 24.04 LXC container with a 1GB limit, booted and left alone, used 68 MiB of host memory, page cache included. An Ubuntu 24.04 VM built from the cloud image with 2GB assigned was holding 1,941 MiB of host RAM twelve minutes after boot, with nothing running inside it:
| Idle Ubuntu 24.04 guest | RAM assigned | Host RAM in use | Where we read it |
|---|---|---|---|
| LXC container | 1GB limit | 68 MiB | memory.current of the container’s cgroup |
| VM (cloud image) | 2GB | 1,941 MiB | VmRSS of its kvm process |
The VM figure is not a measuring error. Proxmox’s QEMU asks the host kernel for 2MB transparent huge pages for guest RAM, and 1,864 MiB of that VM’s 1,941 MiB sat in huge pages, so every region the guest kernel touched while booting was claimed on the host in 2MB pieces. Proxmox does enable free page reporting on the balloon device that every VM gets by default (unless you set balloon: 0), so memory a Linux guest actually frees goes back to the host. Page cache does not count as free, though, and an idle guest keeps its cache, so plan each VM at its full assigned size, not at what free reports inside it. The fourteen VMs on pve02 show the same split with real workloads: the Ubuntu 26.04 and Debian 13 VMs held their full 4GB on the host, while Rocky Linux 10 and openSUSE VMs with 4 to 8GB assigned held 1.0 to 1.5GB.
A rough per-guest budget I use when planning a node:
| Guest | Typical RAM to assign |
|---|---|
| Lightweight LXC (Pi-hole, a single service, a reverse proxy) | 256MB to 1GB |
| Idle Linux VM (base server, nothing heavy) | 1 to 2GB |
| App or small database VM (PostgreSQL, a self-hosted app) | 2 to 4GB |
| Plex or Jellyfin VM (transcoding, library cache) | 4 to 8GB |
| Kubernetes worker node | 4 to 8GB |
| Windows Server VM | 4 to 8GB minimum |
These are the amounts to assign, not the absolute minimums. A VM you starve will technically boot and then perform terribly, which is its own kind of waste. Size for the working set, not the floor.
Tame the ZFS ARC (this is the one that surprises everyone)
If you run ZFS on the host, as the root filesystem or as a pool for VM disks, the ARC (Adaptive Replacement Cache) is the single biggest RAM consumer you did not plan for. ZFS uses spare RAM as a read cache, and the more you give it the faster reads get. The trap is the default ceiling.
The Proxmox VE installer caps the ARC at 10% of host RAM, clamped to 16GiB max, by writing a line to /etc/modprobe.d/zfs.conf. That is sane. ISOs from 8.4 onward write that line on every install, whatever the root filesystem, which is why my two XFS-root nodes have it; the 8.1 to 8.3 ISOs wrote it only for a ZFS root. The problem is every host without the line: an install from 8.0 or older, an ext4 or XFS install from the 8.1 to 8.3 ISOs, or Proxmox VE installed on top of plain Debian. The cap is a setting of the ZFS kernel module, not of a pool, so those hosts run on the OpenZFS default, and the default depends on the version. OpenZFS 2.2 and older, which Proxmox VE 8 ships, lets the ARC grow to half of RAM. OpenZFS 2.3 and newer, which Proxmox VE 9 ships, allows all of RAM except 1GiB (or five eighths of it on very small machines). Proxmox VE 8 reached end of life in August 2026, so an old uncapped host upgraded to 9 can hand nearly the whole box to the cache. Check whether yours has the line with cat /etc/modprobe.d/zfs.conf. That is the “ZFS ate my memory” complaint you see on every homelab forum. The cache will give that RAM back under pressure, but VMs and the ARC fighting over the same pages is not a fight you want to referee.
You can see exactly where your ARC is sitting. On my node the cap is set explicitly, and ZFS ships a summary tool:
arc_summary | head -20
The cap and the current size print at the top. Note that the ARC is capped at 6.3GiB and is using 3.3GiB right now, well under its limit:
ARC status: HEALTHY
Memory throttle count: 0
ARC size (current): 51.9 % 3.3 GiB
Target size (adaptive): 95.9 % 6.0 GiB
Min size (hard limit): 31.3 % 2.0 GiB
Max size (high water): 3:1 6.3 GiB
The interesting part is whether that modest cache is actually doing its job. Pull the raw hit and miss counters:
cat /proc/spl/kstat/zfs/arcstats | grep -E '^hits|^misses'
On this node that is 7,771,952 hits against 233,188 misses, a 97% hit ratio from a cache capped at just over 6GiB:
hits 4 7771952
misses 4 233188
That 97% number is the point. You do not need to hand ZFS half your RAM to get an effective cache. A few gigabytes serves the working set on a typical homelab pool, which frees the rest for VMs. So cap it.
The cap still holds four months later under a much heavier load. In October, with 18 guests running across the two nodes, pve01’s ARC sat at 6.10 GiB of its 6.27 GiB ceiling with a 96.9% hit ratio (308,201,067 hits against 9,763,865 misses), and pve02’s at 3.14 GiB with 94.3%. Those counters run from boot, so the ratios cover the nodes’ whole uptime rather than one busy day, but the point stands: a cache of about 10% of RAM answers more than nine reads in ten from memory, and every gigabyte above that stays with the VMs.
The cap lives in that tiny modprobe file. A stock Proxmox host runs as root and ships neither sudo nor the full vim (only nano and vim.tiny), so either drop the sudo prefix and open the file with nano, or install both once with apt install sudo vim (after apt update, and on a fresh node only once you have switched to the no-subscription repository, because the enterprise repository refuses apt update without a subscription). Open the file:
sudo vim /etc/modprobe.d/zfs.conf
Set zfs_arc_max to a value in bytes. If the installer already wrote a line, change its value instead of adding a second one. This caps the ARC at 6GiB (6 multiplied by 1024 three times):
options zfs zfs_arc_max=6442450944
On a ZFS-root system the ZFS module loads from the initramfs, so rebuild it and reboot for the change to stick. On an ext4 or XFS root the module reads the file from disk at boot, and a reboot alone is enough:
sudo update-initramfs -u -k all
sudo reboot
On a ZFS root, skip the rebuild step and the cap silently does nothing after the next boot, because the module never reads your new file. After the reboot, read the ceiling the ARC is actually using from its own statistics rather than from the parameter file, which echoes whatever was requested even when it was ignored. On pve01, which keeps the installer’s 10% line, it prints a c_max line ending in 6730809344:
grep -w c_max /proc/spl/kstat/zfs/arcstats
For the size itself, Proxmox’s own starting point is 2GiB plus 1GiB for every TiB of pool, so an 8TiB pool gets 10GiB. Then watch the hit ratio and adjust. How much pool you have depends on your layout, and the ZFS RAID level you choose changes both usable space and how hard the ARC works. If you are picking SSDs for that pool, the NVMe versus SATA datastore breakdown covers why power-loss protection matters more than raw speed.
Account for KSM, ballooning, swap, and migration headroom
Three Proxmox features quietly stretch the RAM you have, and one workload quietly demands more. Worth knowing all four before you commit to a tier.
KSM (Kernel Same-page Merging) deduplicates identical memory pages across VMs. Run several guests of the same distro and they share a lot of identical kernel and library pages, so KSM reclaims that overlap. Proxmox’s ksmtuned starts the scanner when the memory the VMs actually hold plus 20% of RAM would exceed the total, or when free memory (not counting the ARC) drops below 20% of RAM, and stops it once neither holds. The pages it already merged stay merged until a guest writes to them. On a quiet node you will see pages_sharing at zero, which is normal. On a busy one the counters hint at what KSM is doing, so we read them on pve02:
for f in run pages_shared pages_sharing pages_unshared full_scans; do echo "$f $(cat /sys/kernel/mm/ksm/$f)"; done
With fourteen VMs running, seven of them openSUSE test installs and three more on Rocky Linux 10, the node reported:
run 0
pages_shared 1466447
pages_sharing 5221984
pages_unshared 1048688
full_scans 16
Read those numbers with care. The kernel defines pages_sharing as the page mappings KSM saved, and 5,221,984 pages of 4 KiB would be about 19.9 GiB, but the counter only updates while the scanner runs. With run 0 it still holds the total from the last pass, including merges that guests have since broken by writing to the page, so it overstates the current saving. A better estimate compares two numbers that disagree only because of KSM: each VM process counts every merged page in its own anonymous memory, while the kernel’s AnonPages total counts a merged page once. This short loop adds up the first and prints the second:
for p in /proc/[0-9]*; do [ "$(cat $p/comm 2>/dev/null)" = kvm ] && awk '/^RssAnon/{print $2}' $p/status; done | awk '{s+=$1} END{print "kvm RssAnon kB:", s}'
grep AnonPages /proc/meminfo
Run later the same day on pve02, it printed:
kvm RssAnon kB: 44059240
AnonPages: 33242776 kB
The VM processes claim 10.3 GiB more anonymous memory than the kernel actually holds, so KSM was really saving about 10 to 12 GiB (the range allows for the roughly 2 GiB the host’s own processes hold). On pve01, with four unrelated VMs, the same comparison gave only 1 to 2.5 GiB, although its stale counter suggested 4 GiB. Without KSM, pve02 would show about 15 GiB available instead of 26.5 GiB. The other half of how the node runs 72 GiB of assigned VM memory on 62.4 GiB of usable RAM is that its guests have never touched, or have since handed back, much of what they were given: the host-side RSS of all fourteen VMs added up to 40 GiB, and even that sum counts every shared page once per VM. It is also why KSM stays a safety net rather than a plan: the saving depends on the guests staying alike, and a burst of writes inside them un-merges pages at exactly the moment the host is busiest.
Ballooning lets a VM hand idle RAM back to the host. Set a minimum and a maximum on the guest, and Proxmox reclaims the slack between them when the host gets tight. It helps you overcommit, but a ballooned-down VM that suddenly needs its RAM back can stall, so do not treat the maximum as if it costs nothing.
Swap is your last line of defense, not a capacity plan. The kernel’s swappiness default is 60, and Proxmox’s admin guide suggests 10 for a server so the host keeps guest memory in RAM longer. If a node is regularly swapping under normal load, that is the signal to add RAM, not to grow swap. ZFS-root installs create no swap at all, because swap on a ZFS volume can stall the whole host under memory pressure, so check whether yours has any (swapon --show) and put it on a plain partition if you want it.
Migration and backups are the headroom eater people forget. Live-migrating a 16GB VM to another node, or running a Proxmox Backup Server job, both need working memory on top of your steady-state usage. Leave roughly 10 to 15% of total RAM unallocated as breathing room. A node that is provisioned to 100% has nowhere to put a migrating guest.
Match the RAM tier to what you actually want to run
Now the tiers. With the host base, per-guest budgets, and a capped ARC in mind, this is what each common RAM tier realistically runs in a homelab. The “comfortable load” column assumes ZFS with the ARC capped sensibly and 10 to 15% headroom left free.
| RAM | What it comfortably runs | Honest verdict |
|---|---|---|
| 16GB | The host (~2GB) + capped ARC (~2GB) + 2 light VMs or a handful of LXCs. Think Pi-hole, a reverse proxy, one small app. | A real starter node, but tight. ZFS plus VMs fight for the last few GB. Fine to learn on. |
| 32GB | Host + ARC + 4 to 6 mixed guests: a couple of VMs, several LXCs, a small database, Pi-hole, a reverse proxy, monitoring. | The comfortable small-homelab tier. Most self-hosters never outgrow this. |
| 64GB | Host + ARC + Plex or Jellyfin + several services + one or two Kubernetes nodes, with room to experiment. | Where a homelab stops being cramped. You stop counting megabytes and just spin things up. |
| 128GB | A serious lab: multiple k8s nodes, several databases, a Windows domain, big ZFS ARC, nested virtualization, lots of headroom. | Overkill for most, essential if you run production-like stacks or rent the spare capacity to yourself. |
My own nodes run 64GB each, and the two snapshots show how far the same hardware swings. In June, with most VMs powered off, one node was using around 7GB and the other under 9GB. In October the lab was busy. The used column comes from free, so it already includes the ARC:
| Node (64GB) | VMs running | RAM assigned to VMs | Host RAM used | ZFS ARC | KSM saving |
|---|---|---|---|---|---|
| pve01 | 4 | 40 GiB | 39.1 GiB | 6.1 GiB | about 1 to 2.5 GiB |
| pve02 | 14 | 72 GiB | 35.9 GiB | 3.1 GiB | about 10 to 12 GiB |
Take the ARC out and both nodes hold the same 33 GiB for guests and the host, even though one runs four VMs and the other fourteen. pve01 runs a Jellyfin VM and a dashboard VM that hold every megabyte they are given, and four unrelated guests leave KSM little to merge. pve02 promises more RAM than it physically has and still has room, because most of its guests are similar test installs that never touch their full allocation and deduplicate well. That is the real lesson: provisioned RAM and used RAM are different numbers, and which one you hit depends on the workload, not the VM count. You size for the moment everything is running at once, not for a quiet Tuesday. If you are still choosing the box itself, the homelab mini PC picks for Proxmox call out the RAM ceiling on each model, which matters more than you would think (more on that next).
ECC vs non-ECC, and the SO-DIMM ceiling on mini PCs
Two hardware choices shape what you can actually buy.
ECC versus non-ECC. ECC RAM detects and corrects single-bit errors before they reach your data. For a 24/7 server holding anything you care about, it is the right call. The persistent myth is that ZFS requires ECC or it will corrupt your pool (the “scrub of death”). It does not. The OpenZFS FAQ recommends ECC strongly for enterprise use and points out that without it a flipped bit can go undetected and be written to disk, which is true of any filesystem, while saying that for home users the extra safety may not justify the cost. So: ECC is recommended for a server you trust with real data, but a non-ECC homelab node running ZFS is not a ticking time bomb. Run what your hardware supports and your budget allows.
The catch is that most homelab mini PCs simply cannot take ECC. They use laptop-style SO-DIMM slots and consumer chipsets that do not validate ECC. If ECC is non-negotiable for you, that pushes you toward a workstation or server board that validates it. Most used Dell and HPE towers at homelab prices take DDR4 ECC, while a new build on a W680, Xeon E-2400 or AM5 board uses a DDR5 ECC unbuffered module like this 32GB DDR5-5600 ECC UDIMM from NEMIX (paid link). Always check the board’s QVL first; ECC support is a motherboard feature, not just a RAM feature.
The mini-PC ceiling. This is the constraint that quietly decides your future. A typical homelab mini PC has two SO-DIMM slots, and the ceiling depends on the platform and its BIOS: many current two-slot boxes accept a 2x64GB DDR5 kit for 128GB, while older or budget models stop at 64GB. Some single-slot or LPDDR5 units are soldered and cannot be upgraded at all. So buy the box that can reach the tier you will want in two years, not just the tier you need today. If you land on a 2-slot mini PC, a Crucial 32GB DDR5-5600 SO-DIMM kit (paid link) takes a box that shipped with 2x8GB to a comfortable 32GB without touching the rest of the build. Full-size servers using RDIMM scale into the hundreds of gigabytes, which is why people who run genuinely heavy labs end up on a used rack server rather than stacking mini PCs. The same logic applies to the storage you bolt on; the SSD and NVMe picks for servers and homelab separate the consumer drives from the enterprise ones with power-loss protection.
What I would change for a production-leaning node
If this were carrying anything I genuinely depended on rather than a learning lab, three things change. I would spec ECC RAM on a board that validates it, which alone rules out most mini PCs and points at a used enterprise box. I would cap the ZFS ARC deliberately from day one rather than discovering it after a VM gets OOM-killed, and I would leave a hard 15% of RAM unallocated so live migration and backups always have somewhere to land. And I would buy the node with the highest RAM ceiling I could justify, because the workload always grows and replacing a sold-out mini PC a year later is its own headache.
The short version: a 32GB node is the honest pick for a first real homelab, 64GB is where it stops feeling cramped, and the ARC cap is the one setting you should not skip. Get those right and the RAM question stops being the thing that decides what you can run. For the full first-boot checklist once the box is built, the post-install steps for Proxmox VE include the ARC cap and a few other settings worth doing early.
Great article! Written in a geek, without being too geek, if you know what I mean. Perfect for a retiree turned home-lab hobbyist like me.
Thanks!