A two node Proxmox cluster is the configuration the documentation quietly warns you about, and the one almost every homelab ends up building anyway. Two votes, majority needed, so losing either node leaves one vote out of two. That is not a majority. Corosync drops quorum, /etc/pve remounts read only, and the surviving node can no longer start a guest, edit a config, or migrate anything. Half the cluster is up and it can do nothing.
The textbook fix is a third vote from a small external QDevice arbiter that holds no data.
Why it bites here
In a rack, both nodes are up all the time and a node being down is an incident. In a homelab the second node is down regularly and on purpose: it gets rebooted, it gets used for something else, it gets carried to another room. A quorum model that treats that as an emergency is the wrong model.
The textbook answer is a third vote. Proxmox supports a QDevice: a small external arbiter, typically a Raspberry Pi, running corosync-qnetd, holding one vote and no data. There is a Pi in this lab already. That is still the cleaner long term answer and it is on the list. ๐
The answer actually deployed is the one that needed no new moving parts.
two_node and wait_for_all
Corosync has a votequorum mode for exactly this case:
quorum {
provider: corosync_votequorum
two_node: 1
wait_for_all: 0
}two_node: 1 sets the expected vote count so that a single surviving node is quorate. wait_for_all: 0 is the half people forget, and it is the half that matters. With wait_for_all at its default, a node that boots alone waits to see every other member before it will become quorate. A cold boot of the surviving node then hangs, un-quorate, waiting for a machine that is not coming. โณ
With both set, either node is quorate on its own, cold boots alone, and auto starts its guests. Bump config_version, then reload:
corosync-cfgtool -R # reload on this node, pushes to the cluster
pvecm status | grep -i quorumTake a copy of the working file first. cp /etc/corosync/corosync.conf /root/corosync.conf.bak costs nothing, and a cluster with a bad corosync config is a genuinely bad evening.
| Survives node loss | Cold boots alone | |
|---|---|---|
| Default | no | no |
| two_node: 1 | yes | no |
| Both set | yes | yes |
Either node being quorate on its own is also what makes split brain possible if the link between them partitions.
The trade
It buys: either node reboots alone and comes back working, and the services on the other one never notice.
It costs: split brain is now possible. If both nodes are up and the network between them partitions, both consider themselves quorate, both will write to their own /etc/pve, and the two copies diverge.
That trade is fine here, and it is worth being explicit about why rather than repeating “two node clusters are dangerous” as folklore. Both nodes sit on one switch, one hop apart. The partition scenario needs both machines running and the link between them broken while both stay powered. On a single switch, the failure that takes out the link takes out the switch, and then both nodes are isolated from everything else too. The risk is real, it is just small next to “the second node reboots most weeks”, which is not a risk at all.
RAM, not cores
The other thing a two node homelab teaches quickly is that cores are not the constraint. The primary node has 32 GB and runs close to the line ๐
Ballooning makes that survivable and it also makes it confusing. A guest configured with 2 GB and a balloon minimum of 1 GB, on a host under pressure, reports about 940 MiB usable inside the guest. Nothing is broken. The balloon driver has taken the memory back because the host asked. But a build that assumed 2 GB gets OOM killed, and the message says nothing about ballooning.
Two habits fix most of it. Give every guest swap, even a small file, so a memory spike degrades instead of dying. And check free memory from inside the guest rather than from the config, because the config is a request, not a promise.
Thin pools deserve the same suspicion. Thin provisioning means the sum of the disks you have handed out is already well past what exists. Overcommitting storage is fine right up until it is not, and a full thin pool does not degrade politely.
Moving guests
Migration with local disks is one command and it works online:
qm migrate <vmid> <target-node> --online --with-local-disksThe only snag worth knowing is a leftover install ISO attached to ide2, which blocks migration because the target has no such file. Eject it and the migration runs. ๐ฟ
