Proxmox ZFS pool layout for a one-disk home server
My Proxmox server keeps everything that matters on one 1 TB SSD. A Windows Server VM, a file server, and the whole Plex library all live on a single ZFS pool called ZFSDisk. There is no second disk behind it.
Short version for the skimmers. A good Proxmox ZFS pool layout for a home server is one pool, split into one dataset per job, with at least 10% of the pool kept free. Put media in its own dataset so containers mount only that. Watch how much RAM ZFS takes for its cache. And if the pool is a single disk, know that ZFS can turn it into a mirror later with one command and one more disk.
KEY FACTS
My pool is one 1 TB SSD with no redundancy. The boot drive is a separate 256 GB SSD.
The Windows Server VM disk takes about 520 GB, and its saved snapshot state about 25 GB more. That is over half the pool before any media.
OpenZFS says to keep pool free space above 10%. Past that point the allocator switches to a slower strategy.
Proxmox caps the ZFS cache at 10% of RAM, up to 16 GiB, on ZFS installs made with its installer since 8.1. Otherwise its docs put the default at 50%.
A single disk becomes a two way mirror with one zpool attach and one disk of the same size or larger.
What does my Proxmox ZFS pool layout look like?
Five datasets. Proxmox made four of them on its own when I created the VM and the file server container. I made the media one by hand. You can list yours with this:
zfs list -o name,used,avail,refer,mountpoint -r ZFSDisk
Here is what mine holds and roughly how big each piece is.
| Dataset | What it is | Approx size |
|---|---|---|
| ZFSDisk/vm-102-disk-0 | Windows Server 2025 VM, main disk | ~520 GB |
| ZFSDisk/vm-102-state-FreshInstall | Saved snapshot state of that VM | ~25 GB |
| ZFSDisk/subvol-103-disk-0 | Root disk of the Samba file server container | ~1.25 GB |
| ZFSDisk/vm-102-disk-1 | Small secondary VM disk | ~6 MB |
| ZFSDisk/media | Plex library: movies, tv, music | Growing |
The names tell you who made what. Proxmox names VM disks vm-<id>-disk-<n> and container root disks subvol-<id>-disk-<n>. The VM disks are zvols, which are block devices. The container disk is a normal ZFS filesystem. Media is a filesystem too, and it is the only one I named myself.
The Plex container itself is not on this pool. Its root disk sits on the boot SSD in local-lvm, and it only reaches the pool through a bind mount. That container is its own post: Plex LXC on Proxmox.
How should you split a Proxmox ZFS pool into datasets?
One dataset per job. Proxmox already does this for guest disks, so the only datasets you make by hand are for shared data. For me that is media.
zfs create ZFSDisk/media
mkdir -p /ZFSDisk/media/movies /ZFSDisk/media/tv /ZFSDisk/media/music
The point of a separate dataset is a clean boundary. My Plex container mounts /ZFSDisk/media, not /ZFSDisk. The pool root is where Proxmox keeps guest disks, and nothing in a media container needs to see that. A dataset gives each mount a hard edge.
There is a trap in the other direction too. A bind mount of a parent does not carry its child datasets into the container. You see the top level and empty folders where the children should be. I hit that one early and wrote it up in my Proxmox home server setup. Mount each dataset you need, not the parent.
Two settings are worth a look on a media dataset. OpenZFS’s tuning guide says datasets use a 128K record size by default and suggests recordsize=1M for sequential workloads, which is what streaming large video files is. It also says compression defaults to on since OpenZFS 2.2, which means LZ4. Check both:
zfs get recordsize,compression ZFSDisk/media
zfs set recordsize=1M ZFSDisk/media
A new record size only applies to data written after the change. Files already on the dataset keep the size they were written with.
Ownership is the last piece. My container is unprivileged, so the plex user inside it is 999:990 and the files on the host have to be 100999:100990. Files copied in over Samba arrive as root, so a cron job on the host fixes ownership every five minutes. The why of that offset is in unprivileged LXC permissions.
How full is too full?
OpenZFS puts the line at 10% free. Below that, it says, many of the pool’s internal allocation regions hit a threshold where ZFS switches from first fit to best fit allocation. In plain terms, writes get slower as the pool fills.
On paper that is about 900 GB usable out of my 1 TB. The VM disk and its saved state already take roughly 545 GB. That leaves something like 355 GB for media before I cross the line, and less in practice, because a 1 TB disk never shows a full 1,000 GB once formatted. zpool list gives the real numbers:
zpool list -o name,size,alloc,free,cap,health ZFSDisk
The CAP column is the one to watch. Keep it under 90%. The single biggest lever I have is that 25 GB snapshot state from a fresh Windows install. It is useful while I still might roll back. It is also 25 GB of a disk that has no backup behind it.
How much RAM does ZFS take on Proxmox?
ZFS keeps a read cache in RAM called the ARC. Proxmox’s documentation says new installs since Proxmox VE 8.1 set the ARC limit to 10% of physical memory, clamped to 16 GiB. The installer writes that limit when you pick ZFS during install. Otherwise the docs put the default at 50% of host memory.
That difference matters on a 32 GB box. 10% is about 3.2 GB. 50% is 16 GB, half the machine. My boot drive is LVM, not ZFS, so the installer never offered that limit. I check the real value instead of assuming one:
cat /sys/module/zfs/parameters/zfs_arc_max
arc_summary | head -40
A 0 in zfs_arc_max means no override is set and ZFS is using its built in default. To pin a limit, write it in bytes. This sets 4 GiB, overwrites any existing zfs.conf, and takes effect after a reboot:
echo "options zfs zfs_arc_max=4294967296" > /etc/modprobe.d/zfs.conf
update-initramfs -u -k all
Proxmox’s own sizing advice is at least 2 GiB plus 1 GiB per TiB of storage. For one 1 TB pool that is about 3 GiB. The ARC is designed to shrink when other processes need memory. A big one still makes the host’s memory graph look fuller than it is, which is worth knowing before you start shrinking containers.
Single disk, mirror or RAIDZ for a home server?
This is the part of my layout I would not copy. A single disk pool still checksums every block, so ZFS will tell you when data is corrupt. It just has no second copy to repair it from. I wrote about what that means for backups in my Proxmox backup strategy.
Here is how the common layouts compare with 1 TB disks. The minimum disk counts for RAIDZ come from the Proxmox ZFS documentation.
| Layout | Min disks | Usable space | Disk failures survived | Fits a home server when |
|---|---|---|---|---|
| Single disk | 1 | 1 TB | 0 | You have a real backup somewhere else |
| Mirror | 2 | 1 TB of 2 TB | 1 | You want redundancy with the fewest disks |
| RAIDZ1 | 3 | about 2 TB of 3 TB | 1 | You need capacity more than speed |
| RAIDZ2 | 4 | about 2 TB of 4 TB | 2 | You have big disks and long rebuilds |
RAIDZ usable space is approximate. Parity and padding take a bit more than the clean math suggests, and VM disks on RAIDZ can lose more to padding than files do. For a home server with two to four SATA ports, a mirror is the simple answer. It is also where my plan goes next.
How do you turn a single disk pool into a mirror?
There are two routes. The OpenZFS manual for zpool attach says that attaching a new device to one that is not already mirrored turns it into a two way mirror, then starts a resilver. The new disk adds redundancy once the resilver finishes. Nothing has to be migrated and guests keep running.
zpool status ZFSDisk
zpool attach -w ZFSDisk /dev/disk/by-id/<current-disk> /dev/disk/by-id/<new-disk>
zpool status ZFSDisk
Use the device name exactly as zpool status shows it for the first argument, and a /dev/disk/by-id/ path for the new disk so the name survives a reboot. The -w flag makes the command wait until the resilver is done. The new disk has to be the same size or larger.
The plan I wrote down for this server is the other route: buy two new SSDs, build a fresh mirrored pool, and move things over in stages.
| Attach one disk to ZFSDisk | New mirror pool from two disks | |
|---|---|---|
| Disks to buy | 1 | 2 |
| Data to move | None, the resilver copies it | Media first, then the VM |
| Work involved | One command, then wait for the resilver | Planned moves, guest by guest |
| Old disk afterwards | Half of the mirror | Free to become a backup target or spare |
| Total storage at the end | 1 TB mirrored | 1 TB mirrored plus a spare 1 TB |
Attach is cheaper and quicker. The new pool ends with a disk left over, and on this server a spare disk is exactly what backups need. Neither has happened yet. The first step is the boring one, and it is the one blocking both: run lsblk and find out how many free SATA ports the board actually has.
One more thing a mirror does not fix. It protects against a dead disk. It does nothing about a bad command, ransomware, or a fire. Those still need a backup on different hardware.
FAQ
What is the best ZFS pool layout for a Proxmox home server?
One pool split into one dataset per job, kept under 90% full. Proxmox creates the VM and container datasets itself; make shared data like media its own dataset. With two disks, make the pool a mirror.
Can I convert a single disk ZFS pool to a mirror later?
Yes. Run zpool attach with the pool, the existing disk, and a new disk of the same size or larger. OpenZFS turns the single disk into a two way mirror and resilvers the data onto the new disk while the pool stays online.
How full should a ZFS pool get?
OpenZFS says to keep free space above 10%. Below that, allocation switches from first fit to best fit and writes slow down. Watch the CAP column in zpool list and keep it under 90%.
How much RAM does ZFS use on Proxmox?
Since Proxmox VE 8.1 the installer sets the ARC limit to 10% of RAM, up to 16 GiB, when you install on ZFS. Otherwise the documented default is 50% of host memory. Check zfs_arc_max under /sys/module/zfs/parameters to see yours.
Should I bind mount the ZFS pool root into a container?
No. Mount the specific dataset, like /ZFSDisk/media. The pool root is where Proxmox keeps guest disks, which a media container has no reason to see, and child datasets do not come through a bind mount of their parent anyway.
The short version
One pool, one dataset per job, media in its own dataset, and never more than 90% full. Check what the ARC is allowed to take before you blame a container for eating RAM. If you start on one disk like I did, the way out is a single zpool attach. The SATA port count decides whether that or a new pool is the cheaper route.
This pool is one piece of a bigger build. The plain text prompt I used to plan the whole server with Claude, storage included, is here: the Proxmox home server prompt.
Stay in the loop.
No spam, just signal.
I send one email when I publish something worth reading. Stock deep dives, new projects, tech breakdowns, and what I'm learning from building in public.
Free forever. Unsubscribe anytime. I respect your inbox.