# Proxmox Cluster Pre-Flight Checklist

**Version 2.1 · CC BY 4.0 · https://everettkildare.com/downloads**

Work through this before `pvecm create`. Roughly half of these items are difficult
or impossible to change once the cluster carries production workloads — the ones
marked **one-way** cannot be undone without destroying and rebuilding the cluster.

---

## 1. Quorum

- [ ] **Odd node count**, or an even count with a QDevice arbitrator configured
- [ ] Corosync on **dedicated NICs**, not shared with storage or VM traffic — **one-way** in practice, because moving the ring later means a maintenance window on every node
- [ ] A **second Corosync ring** on a physically separate path (`ring1_addr`)
- [ ] Link priorities set explicitly; do not rely on the discovery order
- [ ] Latency on the Corosync path measured and **below 5 ms**, verified under load rather than on an idle network
- [ ] Fencing behaviour understood and accepted by the change board — a node that loses quorum **self-fences and reboots**, and any running guest goes with it
- [ ] `expected_votes` understood for the two-node case, and `two_node: 1` set only if the implications are accepted

> A cluster that loses quorum stops. That is the design, not a fault. Decide now
> what happens to the site when the Corosync path fails, because the answer at
> 03:00 will be "everything rebooted simultaneously".

## 2. Storage

- [ ] Storage model chosen: **ZFS + replication**, **Ceph**, or a **shared LUN** — effectively **one-way**
- [ ] If **Ceph**: five nodes minimum, 25 GbE or better, enterprise NVMe with **power-loss protection**
- [ ] If **Ceph**: `size=3, min_size=2` accepted, and the usable-capacity arithmetic signed off by whoever is paying
- [ ] If **Ceph**: public and cluster networks separated
- [ ] If **ZFS replication**: the resulting **RPO agreed in writing** — replication is asynchronous, so the exposure is the replication interval, not zero
- [ ] If **ZFS**: `ashift` correct for the underlying devices — **one-way**, only fixable by recreating the pool
- [ ] If **ZFS**: ECC memory, and ARC sizing left with headroom for guests
- [ ] Snapshot capability verified **against the chosen backend**, not assumed — LVM-thin, ZFS, Ceph RBD and NFS do not behave identically
- [ ] Consumer SSDs explicitly ruled out for any write-intensive role
- [ ] Discard/TRIM path confirmed end to end if the backing store is thin-provisioned

## 3. Networking

- [ ] A single **VLAN-aware bridge**, not a bridge per VLAN
- [ ] Bond hash policy set to **`layer3+4`** — the default `layer2` pins each pair of hosts to one physical link, so a two-host transfer never exceeds a single link's bandwidth
- [ ] Switch-side LACP configuration matches the host-side bond mode
- [ ] **Jumbo frames** end to end on the storage path, verified rather than configured:
      `ping -M do -s 8972 <peer>` must succeed, and must fail at `-s 8973`
- [ ] MTU consistent across hosts, switches **and** the guest side
- [ ] Management interface reachable independently of the VM bridge
- [ ] Out-of-band access (IPMI/iDRAC/iLO) tested from outside the cluster's own network
- [ ] Spanning-tree edge/portfast set on host-facing ports

## 4. Backup

- [ ] **Proxmox Backup Server on separate hardware** — a backup on the cluster it protects is not a backup
- [ ] **QEMU guest agent installed in every VM**, so snapshots are filesystem-consistent
- [ ] Backup jobs scheduled, with the window sized against the actual change rate
- [ ] **Verification jobs scheduled** — PBS verify, not just "the job said OK"
- [ ] Retention (`keep-daily`/`keep-weekly`/`keep-monthly`) set deliberately
- [ ] Off-site copy or sync target configured
- [ ] **A restore actually performed and timed**, with the elapsed time recorded — this is the single most commonly skipped item on this list, and the only one that proves the rest of the section works

## 5. Before you run `pvecm create`

- [ ] All nodes on the **same Proxmox VE version**, fully updated
- [ ] Time synchronised across every node (`chrony`), verified in sync
- [ ] `/etc/hosts` resolves every node name on every node
- [ ] Root SSH between nodes working
- [ ] The **cluster name decided** — **one-way**
- [ ] Node names decided — a node cannot be renamed once joined
- [ ] Enterprise or no-subscription repository selected consistently
- [ ] A written rollback plan for the first join failing

---

## Post-build verification

Run these before the cluster carries anything real:

```bash
pvecm status                 # quorum present, expected votes correct
corosync-cfgtool -s          # every ring shows "connected", no faults
ha-manager status            # HA services where you expect them
pvesm status                 # every storage active on every node
journalctl -u corosync -b    # no retransmit warnings
```

Then pull a Corosync cable and watch what happens. Do it now, deliberately,
with nothing running — not later, accidentally, with production on top.
