Skip to main content
RunBook Academy

Proxmox VEVIII · CephCeph disaster recovery

RBD mirroring for cross-site replication

Expert⏱ ~30 minrbdceph

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

Not yet marked complete on this device.

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-basedSnapshot-based
Required image featuresexclusive-lock, journalingexclusive-lock
Write path costEvery write is written twiceNone on the write path
RPONear-continuousThe snapshot interval
GranularityEvery write, in orderDelta between two mirror snapshots
EnabledPer pool or per imagePer 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

Configuration changeon site-a and again on site-b
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" image

The 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.

Configuration changeon site-a: create the token
POOL=pve-vms
rbd mirror pool peer bootstrap create \
--site-name site-a "$POOL" > /root/site-a-token
Configuration changeon site-b: import it
POOL=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-token

Pick 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

Configuration changeon site-b: create the daemon user and start it
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

Configuration changeon site-a: opt an image in
POOL=pve-vms
IMAGE=vm-101-disk-0

rbd mirror image enable "$POOL/$IMAGE" snapshot

rbd mirror snapshot schedule add \
--pool "$POOL" --image "$IMAGE" 15m

A 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.

Read-only / Safethe daily check
POOL=pve-vms
rbd mirror pool status --verbose "$POOL"
rbd mirror pool info "$POOL"
Read-only / Safe
$ rbd mirror pool status --verbose pve-vms
health: 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:02

Illustrative 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

Service impact possibleon site-a: demote, then let the last delta ship
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:

Service impact possibleon site-b: promote
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

Data-loss riskon site-b: forced promotion
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:

Data-loss riskon the site whose copy you are discarding
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 mirroringProxmox Backup Server
Protects againstLoss of a site or a clusterLoss of data, at a point in time
RPOMinutesHours to a day
Recovery point choiceThe current state onlyAny retained snapshot
Ransomware in a guestReplicated within minutesRecoverable from before it
Accidental rm -rfReplicated within minutesRecoverable from before it
Guest configurationNot includedIncluded in the backup
VerificationManual failover testproxmox-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 stays OK while 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 2 to 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 journaling feature, so use image mode and opt in per image.
  • The rbd-mirror daemon runs at the receiving site; run more than one.
  • Your real RPO is the gap between local_snapshot_timestamp and remote_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 resync discarding 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

  1. 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?

  2. 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?

  3. 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.

  4. 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.