Open a shell on any Proxmox VE node and run ls /etc/pve, and you'll see something odd. Every VM's config file is sitting right there, even ones that live on a completely different physical machine three racks away. There's no NFS mount, no rsync cron job, nothing you configured. It just works, all the time, on every node.

That's pmxcfs — the Proxmox Cluster File System — and it's one of those things that quietly runs your whole setup without ever asking for attention. Most people never think about it until something goes wrong: a node won't boot, the web UI throws a permissions error nobody's ever seen, or /etc/pve suddenly turns read-only. At that point, understanding what pmxcfs actually is stops being trivia and starts being the thing that gets you unstuck.

What You Will Learn

By the end of this one you'll know what pmxcfs actually is under the hood — not just "the folder where config lives," but the FUSE filesystem, the SQLite database, and the Corosync layer that ties it all together. You'll know why some files show up identically on every node while others are node-specific, what those dotfiles like .version and .members are for, and what "local mode" recovery actually does when a node loses quorum. None of this requires a cluster to follow along — a single standalone node runs pmxcfs too, just with a cluster of one.

What Is This Feature?

pmxcfs is a database-driven filesystem that Proxmox VE mounts at /etc/pve on every node. "Database-driven" is the key part — unlike a normal directory of files sitting on your disk, everything under /etc/pve is really a view into a SQLite database stored at /var/lib/pve-cluster/config.db. The filesystem layer on top, built with FUSE (Filesystem in Userspace, a way for a regular program to act like a filesystem without needing kernel driver code), just presents that database as files and folders so tools like qm, pct, and the web UI can read and write to it the normal way.

The service behind all of this is called pve-cluster, and it's what actually mounts /etc/pve — if you stop that service, the mount point goes empty until it starts again. On a clustered setup, pve-cluster also talks to Corosync (the cluster communication layer that keeps nodes in sync and handles voting on whether the cluster has quorum) to replicate every write to every other node in real time. Change a VM's config on node A, and node B sees the identical change within a fraction of a second, no polling involved.

There's a hard ceiling on how big this can get: the whole database is capped at 128 MiB, because a full copy of it lives in RAM on every node for speed. That sounds small, but it's plain text configuration — VM definitions, container configs, storage and network settings — not disk images or backups, so 128 MiB comfortably holds configuration for several thousand guests. You will not run into this limit on a homelab, or honestly on most production clusters either.

A few quirks fall out of building a filesystem this way. You can't create symlinks inside /etc/pve, and you can't rename a non-empty directory — that second restriction exists specifically to stop two VMs from ending up with the same ID during a rename. Standard POSIX permission bits mostly don't apply either; access is controlled by Proxmox's own permission system layered on top, not by chmod.

Why Would You Use It?

You don't really "use" pmxcfs the way you'd use a feature you toggle on — it's running underneath everything from the moment Proxmox VE is installed, cluster or not. What's worth understanding is what it buys you and where its limits are.

  • Every node agrees, instantly. There's no "give it a minute to sync" — a config change is either accepted and replicated everywhere, or it fails because quorum isn't there. That's a much stronger guarantee than something like rsync running on a timer.
  • One source of truth for configuration. VM and container configs, storage definitions, firewall rules, user permissions — all of it lives in the same database, so backing up config.db effectively backs up your entire cluster's configuration state.
  • It fails safe, not silently. If a node can't reach enough of the cluster to have quorum, pmxcfs drops /etc/pve into read-only mode on that node rather than letting it accept changes that might conflict with what other nodes are doing. That's the split-brain protection working exactly as intended.

What it doesn't do is store your actual VM disks, ISOs, or backups — those live on whatever storage you've configured (local disk, ZFS, NFS, Ceph, whatever). pmxcfs is strictly the configuration layer: the "what should exist and how it's configured," not the "here's 40GB of Windows install."

Prerequisites

  • Root or sudo access on a Proxmox VE node — a single standalone node is fine, you don't need a cluster to follow along.
  • Basic comfort in a Linux terminal. Nothing here is destructive if you just look around, but a couple of commands later touch a running service.
  • Ideally a test or homelab node rather than something serving production VMs, if you plan to try the local-mode recovery example.

Step-by-Step Tutorial

Step 1: Confirm the service is running

Everything under /etc/pve depends on one systemd service:

systemctl status pve-cluster

You're looking for "active (running)." If this service isn't running, /etc/pve will be an empty directory — not an error, just nothing there, because nothing's mounted it yet.

Step 2: Look at what's actually in there

ls -la /etc/pve

You'll see directories like nodes, priv, and a handful of files sitting at the top level — corosync.conf (on clustered systems), storage.cfg, user.cfg, and more. You'll also notice three symlink-looking entries: local, qemu-server, and lxc. These aren't real symlinks in the usual sense — remember, pmxcfs doesn't support those — they're special pointers pmxcfs generates itself, and local always resolves to nodes/<your-hostname>. That's how the same command works identically on every node without you having to know or type the hostname.

Step 3: Check the node list and dotfiles

ls /etc/pve/nodes

On a cluster, every joined node gets a directory here, each holding that node's own VM and container configs under qemu-server/ and lxc/. Now look at the hidden status files sitting at the root of /etc/pve:

cat /etc/pve/.version
cat /etc/pve/.members

.version is a running counter that increments on every write to the filesystem — it's how nodes can quickly tell if they're out of sync without comparing every file. .members shows you which nodes pmxcfs currently considers part of the cluster and whether each one is online. There's also a .vmlist that lists every VM and container ID across the whole cluster, and .clusterlog, which keeps the last 50 cluster-related log entries.

Step 4: Find the actual database file

ls -lh /var/lib/pve-cluster/config.db

This is the real, physical file backing everything you just looked at in /etc/pve. On a modest homelab cluster it's usually a few megabytes — nowhere near that 128 MiB ceiling. If you ever need to move a node's configuration to new hardware after a full failure, this is the one file that matters (with the service stopped first, and the destination's hostname sorted out before you start it back up).

Step 5: Understand read-only mode (without breaking anything)

If you're on a cluster and want to see quorum status directly, run:

pvecm status

Look at the "Quorate" line. If a node ever shows "No" there, any write attempt under /etc/pve on that node — creating a VM, editing a config, anything — will fail, and that's deliberate. It's not a bug, it's pmxcfs refusing to let a potentially isolated node make changes that could conflict with the rest of the cluster once connectivity comes back.

Commands Explained

CommandWhat it does
systemctl status pve-clusterShows whether the service that mounts /etc/pve is running, and how long it's been up.
ls /etc/pveLists the configuration filesystem's contents — VM configs, storage definitions, cluster status files.
cat /etc/pve/.versionPrints the current write-counter for the whole filesystem, used internally to detect out-of-sync nodes.
cat /etc/pve/.membersShows every node pmxcfs knows about and its current online/offline status.
pvecm statusReports cluster-wide quorum state — whether this node currently has enough votes to accept writes.
pmxcfs -lStarts pmxcfs in forced local mode, ignoring corosync.conf and treating the node as quorate on its own. Used only for recovery — never on a healthy cluster.

Common Errors

  • "Permission denied" writing to a file directly under /etc/pve. Most files there aren't meant to be hand-edited outside the normal Proxmox tools. Some, like corosync.conf, genuinely require root and a very specific edit process, not a quick nano session.
  • /etc/pve is completely empty. Ninety percent of the time this means pve-cluster isn't running. Check systemctl status pve-cluster before assuming your configuration is gone — it almost certainly isn't.
  • Web UI or CLI commands hang, then time out, on config changes. A classic sign of lost quorum. The node can't safely commit the write, so it waits, then gives up.
  • "Configuration file already exists with different UID" during a restore or move. pmxcfs is refusing to silently overwrite something that already has an identity elsewhere in the cluster — check for a duplicate VMID before forcing anything.

Troubleshooting

If /etc/pve looks empty or stale, start with the service itself rather than digging through logs first:

systemctl status pve-cluster
journalctl -u pve-cluster -n 50

The journal usually names the actual problem in plain language — a corosync connection failure, a database that failed to open, that kind of thing. Restarting the service (systemctl restart pve-cluster) fixes plenty of transient issues, but do it knowing it will briefly drop the mount and reconnect.

If quorum is the issue and you're locked out of making changes on an otherwise-healthy single node — say, the rest of your small cluster is down for hardware work and you need to make an emergency change — that's what local mode is for. Stop the service, then start pmxcfs manually with -l:

systemctl stop pve-cluster
pmxcfs -l

This makes the node treat itself as quorate regardless of what corosync.conf says, so you can write to /etc/pve again. I want to be blunt about this one: it's a break-glass tool, not a routine fix. Any changes you make while other nodes are unreachable can conflict with what they still believe is current once they come back online. Use it, make the one change you actually need, then get the cluster reconnected properly and verify things line up before trusting it again.

For a genuinely dead node — motherboard failure, drive died, whatever — the recovery path is to stop pve-cluster on a working node, copy its /var/lib/pve-cluster/config.db onto the replacement hardware, adjust the hostname and node-specific bits to match, and let a fresh pmxcfs mount take it from there. It's more involved than it sounds and worth practicing once on a spare VM before you need it for real.

Best Practices

  • Never edit files under /etc/pve with a text editor as a first instinct. Use qm, pct, or the web UI, which know how to write correctly-formatted changes and trigger the right internal updates.
  • If you're scripting anything that touches /etc/pve directly, check .version before and after, so you can tell whether your change actually landed.
  • Back up /var/lib/pve-cluster/config.db as part of your regular host backup routine, separately from VM backups. Losing VM disks is bad; losing every VM's configuration at the same time is worse.
  • Treat pmxcfs -l as an emergency tool, not a habit. If you find yourself reaching for it often, that's a sign your cluster's network reliability needs attention, not that local mode is a normal workflow.
  • Don't panic the first time you see /etc/pve go read-only. Check pvecm status before touching anything else — it's almost always a quorum event that resolves itself once connectivity is restored.

Frequently Asked Questions

Does a single standalone node use pmxcfs too?

Yes. Every Proxmox VE install runs pmxcfs and mounts /etc/pve, whether or not it's part of a cluster. A standalone node is just a cluster of one, always quorate on its own.

Can I just edit files in /etc/pve directly with a text editor?

You can, technically, but it's a bad habit. Use qm, pct, or the web interface instead — they validate what they write and keep the internal version counter and replication in sync properly.

What happens to /etc/pve if I stop the pve-cluster service?

The mount disappears and the directory appears empty. Nothing is deleted — the data is still sitting safely in config.db — it just isn't mounted until the service starts again.

Is the 128 MiB limit something I should actually worry about?

Almost never. That's plain-text configuration data, not disk images, so it comfortably covers several thousand VMs and containers. Homelab and small business clusters are nowhere close.

What's the difference between pmxcfs and Corosync?

Corosync is the communication and voting layer — it decides who's part of the cluster and whether there's quorum. pmxcfs is the filesystem that uses Corosync to replicate configuration data once quorum says it's safe to do so. They work together, but they're solving different problems.

Conclusion

pmxcfs is the reason Proxmox VE feels consistent no matter which node's shell you happen to be sitting in — one database, replicated in real time, presented as an ordinary-looking folder. Most days you'll never think about it, and that's the point of good infrastructure plumbing.

Where it actually matters is the day something breaks: an empty /etc/pve, a stuck write, a node that's gone read-only. At that point, knowing it's pve-cluster mounting a SQLite database over FUSE — not some mysterious black box — turns a confusing outage into a checklist you can actually work through.