ProxmoxGuide
Isometric technical illustration of a Proxmox Backup Server datastore showing deduplicated chunk storage, prune scheduling, garbage collection, and a verified restore path
backup

Proxmox Backup Server Setup: Dedup, Prune, and Restores

How to set up Proxmox Backup Server: how chunk deduplication works, why it beats vzdump, prune and GC scheduling, and how to verify restores.

By ProxmoxGuide Editorial · · 7 min read

Proxmox Backup Server (PBS) is a separate product from Proxmox VE, and the four things worth understanding before you install it are:

  • Deduplication is content-addressed. Backups are split into chunks named by their own checksum, so identical data across snapshots, across guests, and across hosts is stored once.
  • It replaces the full-archive model of vzdump. After the first run, PVE uploads only the chunks that changed instead of rewriting a complete archive every night, and for a running VM it usually only has to read the changed blocks too.
  • Prune and garbage collection are two separate jobs. Pruning marks snapshots for removal. Only garbage collection frees disk space, and only after a grace period.
  • Verify jobs prove the chunks, not the restore. Verification confirms the data on disk still matches its checksums. It says nothing about whether the guest boots. That test is yours to run.

For one node and four VMs, plain vzdump is fine. Past that, PBS earns its keep the first time you want thirty days of daily snapshots without thirty full copies.

What PBS changes versus vzdump

vzdump produces one self-contained archive per backup: a compressed VMA image for VMs, a compressed tar for containers. Every run is a full backup, so storage cost scales linearly with retention. Twenty daily snapshots of a 200 GB VM is twenty full copies, minus compression.

PBS breaks that link. The client splits each disk image into fixed-size chunks (typically 4 MiB), identifies each by the SHA-256 checksum of its contents, and the server stores it compressed under a digest-named path in the datastore. For every chunk, that digest decides whether it needs uploading or can simply be indexed because the datastore already holds it. File-level backups (containers, and host backups made with the standalone client) go into a pxar archive chunked by a rolling hash instead, so inserting bytes mid-file shifts chunk boundaries locally rather than invalidating the rest of the stream.

A snapshot of a mostly idle VM therefore costs roughly its delta, not its size. The other half of the win is on the read side: for a running VM, QEMU keeps a dirty bitmap of blocks changed since the last backup, so PVE never reads the untouched parts. That bitmap lives inside the running QEMU process, so it is dropped when the guest is shut down, when the QEMU process is restarted for any reason (a host reboot, a qm reboot, a QEMU package upgrade), or when a disk is resized. Live migration does not drop it; Proxmox migrates the bitmap along with the VM. When the bitmap is gone, the next backup has to read the whole disk again. It still only uploads chunks the server lacks, so storage and network cost stay low even when read cost does not.

Deduplication is global across the datastore, so ten Debian VMs from the same cloud-init template share most of their base image chunks. One caveat: with client-side encryption, chunks only deduplicate among backups using the same key. That is by design. PBS derives an encrypted chunk’s digest from the plaintext combined with the encryption key, so the same block encrypted under two different keys produces two different digests and two stored chunks. The key lives on the PVE side, and losing it makes the backups permanently unreadable, so keep a copy somewhere that is not the cluster.

Standing up the server

The most important decision here is physical, not configuration: PBS must not depend on the thing it is protecting. A PBS VM on the cluster it backs up is not a backup, because if that cluster’s storage dies, so does the backup server. A small separate box with a lot of disk and not much CPU is the normal homelab answer.

Two install paths: the PBS ISO, a Debian-based appliance install in the same shape as the Proxmox VE installer, or the proxmox-backup-server package on an existing Debian system. Either gives you the web UI on port 8007 and the usual choice between the enterprise and no-subscription repositories.

For the datastore filesystem, plan for metadata and random reads, not throughput. Garbage collection and verify jobs walk the entire chunk store, spread across tens of thousands of subdirectories. On spinning disks that works, but it is slow and gets slower as the datastore grows. If you are running the datastore on ZFS, a mirrored special vdev on SSD is a reasonable thing to consider for the metadata side, though that is an inference from the workload shape rather than a documented Proxmox recommendation; pool layout otherwise follows the rules in the Proxmox ZFS storage guide. ZFS is not required for integrity, since PBS checksums every chunk itself.

Before connecting PVE, create a dedicated user or API token for the hypervisor with a role that can write and read backups but not prune or delete them. PBS separates those privileges deliberately: if your PVE host is compromised, backup-write credentials let an attacker add garbage but not erase your history. Cheapest ransomware mitigation available. You will also need the server’s TLS certificate fingerprint when adding the storage on the PVE side.

Building the backup job

Add the PBS storage under Datacenter, then create the job under Datacenter, Backup. The fields that matter:

  • Mode. Snapshot is the default and correct for almost everything. Stop mode is for guests where a cold, definitely-consistent image beats uptime.
  • Guest agent. Install the QEMU guest agent in your VMs. It lets PVE freeze the guest filesystem for the instant the snapshot is taken, the difference between a filesystem-consistent backup and one needing a journal replay on restore. Databases still want their own dump on top.
  • Schedule. Calendar-event syntax, same as systemd timers. Stagger jobs so one datastore is not taking thirty guests at once.
  • Notifications. Configure a target and confirm a failure actually reaches you. The failure worth guarding against is rarely a corrupt archive; it is a job that quietly stopped running months ago.

Recent PVE versions also offer backup fleecing. During a backup, QEMU holds a guest write to a not-yet-backed-up block until the old data has been sent to the backup target, so a slow target drags on guest I/O. Fleecing parks that old data in a local fleecing image instead, breaking the dependency. It is worth enabling if guests get sluggish during the window, but it is not free: you have to nominate a fleecing storage, and it should be fast local storage with discard and thin provisioning or sparse file support, with room for the churn. Containers take a different path since there is no block device to bitmap, one more entry in the broader LXC versus VM tradeoff.

Prune and garbage collection are not the same job

Retention in PBS is expressed as keep-last, keep-hourly, keep-daily, keep-weekly, keep-monthly, and keep-yearly. These are not additive buckets of separate copies. One snapshot can satisfy several rules at once, and a snapshot kept by any rule survives. Preview before you commit: PBS shows you which snapshots a given policy marks for removal, and Proxmox publishes a prune simulator for working out a schedule on paper. A policy that reads as conservative can be aggressive in practice.

Set retention in one place. You can configure it on the PVE backup job and on the PBS datastore, and if you do both, the more aggressive of the two is what you actually end up with. Configure it on PBS, where the data lives.

Pruning removes the snapshot’s index files. It does not remove chunk data, because other snapshots may still reference the same chunks. Space comes back only when garbage collection runs. GC is a two-phase mark and sweep. Phase one reads every index and touches the chunks they reference, updating each chunk’s access time. Phase two walks the chunk store and deletes anything whose access time falls outside the cutoff, which is 24 hours and 5 minutes before the GC started, or the start of the oldest running backup if one is in flight. That grace period keeps an in-flight backup from having its chunks pulled out from under it.

Two consequences. Disk usage does not drop when you prune, so do not panic and prune harder. And GC depends on access-time updates on the datastore filesystem. relatime is fine, and the odd-looking 24-hour-and-5-minute cutoff exists precisely because relatime only refreshes an access time once a day. noatime breaks the mechanism. PBS runs a safety check on this, at datastore creation and again at GC, and it is enabled by default; do not switch it off to make a complaint go away.

A workable schedule: prune daily, GC daily or every couple of days in a quiet window, verify on a schedule that overlaps neither. All three are read-heavy and compete for the same disks.

Verification tells you less than you think

A verify job re-reads chunks and confirms each still hashes to its own digest, catching bit rot, a failing disk, and a controller quietly corrupting writes. Schedule it, with the re-verify window set so already-verified snapshots are skipped for some days rather than re-reading the whole datastore nightly.

What verification does not tell you:

  • Whether the guest boots.
  • Whether the application inside comes up with consistent data.
  • Whether you still have the encryption key.
  • Whether anyone knows the restore procedure.

Every one of those has failed for someone with a datastore full of green checkmarks.

Testing restores, properly

Pick a cadence and hold to it. Monthly suits a homelab, more often for anything with real consequences.

Restore to a new VMID, never over the original. Attach the restored guest to an isolated bridge, or no bridge at all, so it cannot fight the production instance for an IP or start talking to real clients. The bridge and VLAN guide covers building that segment.

Then actually log in. Confirm the application starts, the database opens, the data is current to the timestamp you expect. A guest that reaches a login prompt has proven only that the disk restored, which is the easy half.

Test the paths you will reach for under pressure, not just the full restore:

  • File-level restore. PVE can browse inside a PBS VM backup and pull individual files out. Different code path from a full restore, and it is what you want at 2am when someone deleted one directory.
  • Live restore. PVE can start a VM from a PBS backup while data streams in behind it. Excellent for recovery time, and worth confirming before you depend on it.
  • The bare-metal case. If the PVE host is gone entirely, do you have the datastore address and fingerprint, the credentials, the encryption key, and a way to reach the network? PBS stores the guest configuration inside the backup, so the VM definition returns with the disk. Everything upstream is on you.

Write down how long each restore took. That number, not your backup schedule, is your real recovery time objective. If you have not set recovery targets yet, work through the backup and restore strategy and let that drive retention rather than the other way around.

Getting a copy off the box

One datastore in one building is not a backup strategy, it is a single point of failure with good checksums.

PBS sync jobs replicate between PBS instances. The classic arrangement is a pull: the offsite server reaches into the primary and pulls new snapshots. That direction matters, because the credentials then live on the offsite box and an attacker who owns the primary cannot use it to reach out and wipe the remote copy. PBS also supports push direction, which is easier through restrictive firewalls but gives up that property; if you use it, Proxmox’s own advice is a dedicated remote configuration and a dedicated remote user per push job, scoped as tightly as you can stand. Tape is supported too if you want media that is physically offline.

Two settings to watch. remove-vanished controls whether the target deletes snapshots the source no longer has; leaving it off keeps a longer offsite history at the cost of unbounded growth. And the remote datastore needs its own prune, GC, and verify schedules, because a sync target that has never been garbage collected will eventually fill.

Next steps

#proxmox#backup#proxmox-backup-server#deduplication#homelab

Related

Comments