Proxmox VEVIII · CephCeph disaster recovery
RBD mirroring for cross-site replication
What you'll learn
- Choose between journal-based and snapshot-based mirroring for a Proxmox VM workload
- Bootstrap a peer relationship and run the rbd-mirror daemon on the secondary site
- Perform a planned failover and an unplanned one, and know why they differ
- Explain what mirroring replicates and what it therefore cannot protect you from
Prerequisites
Verified against Proxmox VE 9.2.4 · Proxmox Backup Server 4.2.5 · Ceph Squid / Tentacle · Debian 13 (Trixie) · Linux kernel 7.0 (PVE 9.2 default) · 2026-08-12
A size 3 pool with a host failure domain survives a node. A CRUSH rule
with a rack failure domain survives a rack. Neither survives the site,
because every copy is still inside one RADOS cluster and one cluster has
one fate.
RBD mirroring is the answer to that: asynchronous replication of block
images between two independent Ceph clusters. It is the piece the
disaster-recovery part needs from Ceph, and it is entirely unmanaged by
Proxmox — no GUI, no pveceph subcommand, no storage plugin. You
configure it with rbd on both clusters and you operate it yourself.
That last point is the one to internalise before anything else in this lesson. Everything here is a Ceph procedure that Proxmox will neither help with nor warn you about.
Two mechanisms, and only one of them is practical for VM disks
| Journal-based | Snapshot-based | |
|---|---|---|
| Required image features | exclusive-lock, journaling | exclusive-lock |
| Write path cost | Every write is written twice | None on the write path |
| RPO | Near-continuous | The snapshot interval |
| Granularity | Every write, in order | Delta between two mirror snapshots |
| Enabled | Per pool or per image | Per image |
The write-path row decides it. The upstream documentation is blunt: “Since each write to the RBD image will result in two writes to the Ceph cluster, expect write latencies to nearly double while using the RBD journaling image feature.”
Doubling write latency on the pool that holds your VM disks is not a trade most estates will accept for an RPO measured in seconds rather than minutes. Snapshot-based mirroring costs nothing on the write path; it takes a point-in-time mirror snapshot on a schedule and ships the delta between it and the last one.
Pool mirror mode interacts with this. “When configured in pool mode,
all images in the pool with the journaling feature enabled are
mirrored.” Since your images will not have that feature, pool mode
mirrors nothing. Snapshot mirroring is enabled per image, so in practice
you set the pool to image mode and opt images in explicitly. That is
also the safer arrangement: a new VM disk is not silently replicated
across a WAN link because somebody created it in the wrong pool.
Building it
Two clusters. Call them site-a (primary) and site-b (secondary).
Both need the rbd-mirror package; the daemon itself runs on the
cluster that receives data.
1. Enable mirroring on the pool, on both sides
POOL=pve-vms
# on site-a
rbd mirror pool enable --site-name site-a "$POOL" image
# on site-b
rbd mirror pool enable --site-name site-b "$POOL" imageThe pool must exist on both clusters with the same name, and the
secondary’s pool should have the same size and min_size as the
primary. A DR copy on a size 2 pool is a DR copy you cannot trust.
2. Bootstrap the peer relationship
The bootstrap token carries the connection details and a cephx credential, so it is a secret. Move it the way you would move a private key.
POOL=pve-vms
rbd mirror pool peer bootstrap create \
--site-name site-a "$POOL" > /root/site-a-tokenPOOL=pve-vms
rbd mirror pool peer bootstrap import \
--site-name site-b \
--direction rx-only \
"$POOL" /root/site-a-token
shred -u /root/site-a-tokenPick the direction deliberately. rx-only is right when site-b exists
solely to receive; it means site-b cannot accidentally push a stale
image back. rx-tx is for an active/active estate where some workloads
are primary at each site, and it is meaningfully harder to reason about
during an incident.
3. Run the daemon on the secondary
apt install -y rbd-mirror
ID=site-b
ceph auth get-or-create "client.rbd-mirror.$ID" \
mon 'profile rbd-mirror' \
osd 'profile rbd' \
-o "/etc/ceph/ceph.client.rbd-mirror.$ID.keyring"
systemctl enable --now "ceph-rbd-mirror@rbd-mirror.$ID"Run it on more than one node at the secondary site. The daemons elect among themselves and share the image set, so a second one is both capacity and redundancy — and a mirroring pipeline that stops because one host rebooted is a pipeline that will be behind when you need it.
4. Enable and schedule per image
POOL=pve-vms
IMAGE=vm-101-disk-0
rbd mirror image enable "$POOL/$IMAGE" snapshot
rbd mirror snapshot schedule add \
--pool "$POOL" --image "$IMAGE" 15mA schedule set at pool level (--pool without --image) applies to
every mirrored image in it, which is usually what you want once you have
more than a handful.
Reading the status, which is the whole job
Configuration is a one-off. Watching replication is the ongoing work, and mirroring fails in the specific way that it keeps reporting success while falling further behind.
POOL=pve-vms
rbd mirror pool status --verbose "$POOL"
rbd mirror pool info "$POOL"$ rbd mirror pool status --verbose pve-vmshealth: OK
daemon health: OK
image health: OK
images: 12 total
12 replaying
DAEMONS
service 4141:
instance_id: 42133
client_id: site-b
hostname: pve-dr-01
version: 19.2.3
leader: true
health: OK
IMAGES
vm-101-disk-0:
global_id: b7c1e1a4-0000-0000-0000-000000000000
state: up+replaying
description: replaying, {"bytes_per_second":18432000.0,"last_snapshot_bytes":8123456789,"last_snapshot_sync_seconds":412,"local_snapshot_timestamp":1786000000,"remote_snapshot_timestamp":1786000900}
last_update: 2026-08-12 09:41:02Illustrative output
Three fields carry all the meaning.
state. up+replaying is healthy: the daemon is running and the
image is being synchronised. up+stopped on the secondary means the
image is primary here, which after a failover is correct and before
one is alarming. down+* means no daemon is servicing the image.
last_snapshot_sync_seconds against the schedule interval. If a
15-minute schedule takes 412 seconds to ship, you have headroom. If it
takes 900, you are exactly at the limit and the next busy hour puts you
behind.
The gap between the two timestamps. That difference, in seconds, is your actual RPO for that image right now. It is the number to alert on, and it is the only honest answer to “how much would we lose”.
Failover
There are two procedures and the difference between them is whether the primary site is reachable. Running the wrong one is how estates lose data.
Planned: the primary is alive
POOL=pve-vms
IMAGE=vm-101-disk-0
VMID=101
qm shutdown "$VMID"
rbd mirror image demote "$POOL/$IMAGE"
# take a final mirror snapshot so the delta since the last scheduled one ships
rbd mirror image snapshot "$POOL/$IMAGE"Wait for the secondary to report the image as up+unknown or otherwise
show that it has caught up, then promote there:
POOL=pve-vms
IMAGE=vm-101-disk-0
rbd mirror image status "$POOL/$IMAGE"
rbd mirror image promote "$POOL/$IMAGE"Zero data loss, because the demotion was propagated and the final snapshot shipped.
Unplanned: the primary is gone
POOL=pve-vms
IMAGE=vm-101-disk-0
rbd mirror image status "$POOL/$IMAGE"
rbd mirror image promote --force "$POOL/$IMAGE"The documentation states what you are doing: “Forced promotion is needed when the demotion cannot be propagated to the peer Ceph cluster… This will result in a split-brain scenario between the two peers and the image will no longer be in-sync until a force resync command is issued.”
You lose everything written to the primary since the last mirror snapshot completed — which is why the timestamp delta you were monitoring is the number that tells you, before you press it, how much that is.
Failback
When site-a returns, both clusters believe their copy is primary. Ceph will not merge them. You choose which one survives, and the other is overwritten:
POOL=pve-vms
IMAGE=vm-101-disk-0
rbd mirror image demote "$POOL/$IMAGE"
rbd mirror image resync "$POOL/$IMAGE"Mirroring is not backup, and the difference is not academic
Both make a second copy. They protect against different things, and substituting one for the other leaves a real hole.
| RBD mirroring | Proxmox Backup Server | |
|---|---|---|
| Protects against | Loss of a site or a cluster | Loss of data, at a point in time |
| RPO | Minutes | Hours to a day |
| Recovery point choice | The current state only | Any retained snapshot |
| Ransomware in a guest | Replicated within minutes | Recoverable from before it |
Accidental rm -rf | Replicated within minutes | Recoverable from before it |
| Guest configuration | Not included | Included in the backup |
| Verification | Manual failover test | proxmox-backup-client verify jobs |
Mirroring is a faithful copy, which means it faithfully copies your mistakes. An encrypted filesystem at the primary site is an encrypted filesystem at the DR site fifteen minutes later, and the DR copy is now the only copy of the encrypted data.
The estates that get this right run both: mirroring for the site-loss scenario with a short RPO, PBS for everything else with retention and verification. They are complementary and neither is optional if you have promised both an RTO and a recovery-point choice.
Common mistakes
- Turning on journal-based mirroring for VM disks. Write latency nearly doubles, permanently, on the pool that hosts everything.
- Configuring mirroring and not starting
rbd-mirror. Everything reports as configured and nothing replicates. - Alerting on
health: OK. It staysOKwhile the RPO grows. Alert on the timestamp delta. - Forced promotion when the primary was merely unreachable. A network partition that heals leaves you with two divergent copies and a choice about which day of work to delete.
- Mirroring the images and not the guest configurations. The disks arrive; the VMs do not exist.
- A DR pool at
size 2to save money. The copy you fail over to has less redundancy than the one you lost. - Deleting mirror snapshots at the DR site to free space. It breaks the delta chain and forces a full resynchronisation across the WAN.
- Treating it as backup. It replicates deletion and encryption as faithfully as it replicates anything else.
Key takeaways
- Snapshot-based mirroring is the practical choice for Proxmox VM images; journal-based mirroring nearly doubles write latency.
- Pool mode only mirrors images with the
journalingfeature, so useimagemode and opt in per image. - The
rbd-mirrordaemon runs at the receiving site; run more than one. - Your real RPO is the gap between
local_snapshot_timestampandremote_snapshot_timestamp, not the schedule you configured. - Planned failover is demote-then-promote and loses nothing. Forced
promotion loses everything since the last mirror snapshot and creates
a split-brain resolved by
resyncdiscarding one side. - Mirroring replicates images, not guest configurations. Replicate
/etc/pve/qemu-server/separately or pre-create the VMs. - Mirroring and PBS solve different problems. Run both.
Knowledge check
Knowledge check · 4 questions
Q1. You enable mirroring on a pool in "pool" mode, add the peer, start rbd-mirror on the secondary, and confirm health: OK. Days later the secondary still contains no images. What is the explanation?
Q2. A DR review asks for the current RPO of a mirrored image. The schedule is 15m, rbd mirror pool status reports health: OK and state up+replaying. Which figure is the honest answer?
Q3. The primary site is unreachable. You run rbd mirror image promote --force at the DR site and start the VMs. Which statements about the resulting situation are true? Select all that apply.
Q4. Because RBD mirroring keeps a second copy of every VM disk at another site, an estate running it with a 15-minute RPO can reasonably drop its Proxmox Backup Server jobs.
Passing score: 75%. Answers are checked in this browser.