Proxmox Backup Server, End to End
Real backups, with the proof restore most guides skip — a PBS VM, a passed-through datastore drive, fleet-wide nightly jobs, and a restore you actually boot.
Why PBS, when Proxmox already has backups?
Proxmox VE's built-in vzdump is fine, in the way a spare tire is fine: it will get you home once, and you would not want to drive on it for a year. Each vzdump backup is a full archive of a VM's disks. Ten VMs backed up nightly is ten full copies a night, kept on a file share, pruned by whatever script or discipline you remembered to set up. Restores work, but nothing verifies the archives are still readable, nothing deduplicates between them, and the folder of .tar.zst files quietly becomes the least understood critical system in the lab.
PBS replaces the archive pile with a chunk store. Every backup is broken into content-addressed chunks; identical chunks — across snapshots, across VMs, across months — are stored exactly once. On top of that you get:
- Incremental-forever backups. The first snapshot is full; every night after that transfers and stores only changed chunks. Nightly restore points stop costing nightly full copies.
- Verify jobs. PBS can re-read and hash-check snapshots on a schedule, so silent corruption is found by a job, not by you, mid-incident, at the worst possible moment.
- Prune and garbage collection as first-class citizens. Retention is a policy on the datastore (keep 14 daily, 8 weekly, 6 monthly, say), and GC reclaims the chunks that fall out of it. The policy lives in one visible place.
- One pane for the whole fleet. Every node's VMs back up to the same datastore over the network, with a scoped API token, so "are we backed up?" is a question with one screen for an answer.
The VMware analogy, if that's your home turf: vzdump is exporting OVFs to a file share on a cron job. PBS is a proper backup appliance with a deduplicated repository and catalog — closer to what you'd expect from a Veeam repository than from a script.
- Treat backups as a system with a catalog and verification, not a folder of archives.
- The deliverable is not "backups run." It is "a restore has been proven."
The two architecture decisions that matter
Everything else in the build is mechanics. Two decisions shape the whole design, and both were made for the same reason: portability of the backups themselves.
Decision 1: PBS runs as a VM, sized small
Backup infrastructure feels like it deserves its own appliance. Resist that. PBS is not CPU-hungry; its work is hashing, compressing, and moving chunks. A VM with 2 vCPU, 4 GB RAM, and a 32 GB system disk handles a home fleet comfortably, and making it a VM means the backup server is itself just another workload the cluster can snapshot and move. Give it a generic CPU type — we standardize roaming VMs on x86-64-v2-AES (think of it as the EVC baseline of the cluster) — so the VM can start on any host, including in a disaster, on whatever hardware survived.
Decision 2: the datastore lives on a whole drive, passed through to the VM
The tempting design is a big virtual disk on shared storage. Don't. Instead, take a large external USB drive (5 TB in our build) and pass it through whole to the PBS VM, then let PBS partition and format it itself.
Why whole-device passthrough wins:
- A PBS datastore is self-describing. It is a directory tree: chunk store, snapshot indexes, and the VM configs ride inside the snapshots themselves. Point a fresh PBS install at an existing datastore directory and it can read everything it needs.
- The drive becomes the disaster-recovery unit. Host dies, cluster dies, the server corner has a flood — plug the drive into any single new Proxmox node, install PBS, attach the datastore, and you can restore every VM definition and disk from one device. No cluster needs to exist first.
- Restores are not hostage to the storage you lost. If the datastore were a virtual disk living on the thing that failed, your backups would have died with the patient.
Inside PBS, create the datastore via Storage/Disks → Directory → Create: Directory on the passed-through device (that step partitions, formats ext4, and mounts it), then add it as a datastore of type Local — not Removable. Removable is for drive rotation workflows; a fixed backup drive is a fixture, and the type should say so.
qm set step on the host in most setups (including Terraform-driven ones — the common providers have no USB block), and it's tied to that host's USB bus. A USB 2.0 port caps you around 35 MB/s; bulk restores will notice. A USB 3 port is worth the re-cable, and the datastore doesn't care which bus it arrived on.- Small VM, generic CPU baseline: the backup server must be able to run anywhere.
- Whole-drive passthrough + a self-describing datastore = the drive alone is your recovery kit.
- Datastore type Local for a fixed drive; GC cadence respects SMR physics.
Build it, patch it, then let it serve
Order matters here. A new machine joins the fleet patched — before it does any work. The sequence below is the one we ran; steps 3–5 are where most casual installs quietly go wrong.
- Get the ISO, and let the checksum be the gate. Download the official PBS installer ISO and verify its SHA256 against Proxmox's published sum before it goes anywhere near a host. If a download mirror or a TLS warning makes you suspicious mid-download, the checksum is still the whole decision: match, proceed; mismatch, delete and fetch again from somewhere else. Never "install it and see."
- Create the VM. However you provision — GUI or infrastructure-as-code — the shape is the design section's: 2 vCPU on a generic baseline, 4 GB RAM, 32 GB system disk, installer ISO attached, start-at-boot enabled.
- Run the installer wizard. Static IP on your infrastructure subnet (example:
192.0.2.24/24), your LAN gateway as gateway and DNS, a hostname likepbs.home.arpa, timezone set correctly — backup schedules and log timestamps are nonsense without it — and the root password straight into your password manager. Not into a notes file. Not into chat. - Swap the repository and update, before anything else. A fresh PBS install points at the enterprise repository, which will not serve updates without a subscription. Switch to the no-subscription repository (GUI → Repositories), refresh, and apply all updates. If a new kernel arrives, reboot now — the machine serves nothing yet, so this reboot is free. This "patch before it serves" step is the one people skip because the box "isn't doing anything yet." That's exactly why it's free. Take it.
- Detach the installer ISO. Boot order will bite you if you don't: a machine that reboots into its installer after the first power event is a classic. Eject the media in the VM config and confirm the boot order prefers the installed disk.
- Pass through the datastore drive and create the datastore, per the design section. Verify from inside PBS: the disk shows with the right capacity and healthy SMART status, and the datastore exists at its mount point.
If you build with Terraform, two pitfalls we paid for so you don't have to:
terraform plan does not prove your endpoint or credentials work. For a from-scratch VM create, the provider may never dial the API until apply — so a plan can pass cleanly against a placeholder example endpoint and fail only at apply time. Read your variable file values explicitly at plan review. Examples in public modules are documentation-range placeholders precisely so they cannot work by accident..terraform.lock.hcl after its first successful init. Otherwise the next machine — or the next you, in six months — resolves a different provider version than the one the build was proven with.- SHA256 is the ISO's passport. No match, no install.
- Repository swap + full update + any reboot happen before the server holds a single backup.
- ISO detached and boot order confirmed before you walk away.
Wire the cluster to PBS (and the token trap)
PBS and the PVE cluster meet through a dedicated backup user and an API token on the PBS side. Least privilege is the design: this identity should be able to write backups to one datastore and do essentially nothing else.
- On PBS, create a user (example:
backup@pbs) and an API token under it (example token name:pve). - Grant the DatastoreBackup role on your datastore to the user — and then, separately, to the token.
- Store the token secret in your password manager at creation time. PBS shows it once. If you lose it, you delete and reissue the token; there is no "show it again."
- On the PVE side, add PBS as cluster storage (type: Proxmox Backup Server) using the PBS address, the datastore name, and the token credentials. The fingerprint check PVE prompts for is real: compare it against the fingerprint shown in the PBS dashboard before accepting.
- Confirm the new storage appears on every node. Backups are a cluster-wide resource, not a per-host arrangement.
Step 2 deserves its own spotlight, because it is the single most likely place this whole build fails:
500 Can't find datastore, which sounds like a typo hunt and is nothing of the kind. The fix is one more grant: the same role, on the same datastore, to the token. Keep both grants deliberately: the user is your human seat on PBS; the token is the machine principal the cluster actually authenticates as.And the standing security notes, because a backup server is a high-value target wearing a helpful name tag:
- The token secret lives in the password manager only — never in git, never in a spreadsheet of lab notes, never pasted into a chat.
- The PBS web UI (port 8007) gets the same treatment as every other admin door in the lab: reachable on the private network / overlay network only, never forwarded from the internet. And while you're there: the UI's default self-signed certificate is fine for day one behind that door, but replacing it with a properly issued certificate (the same automation you use for your hypervisor UIs) is a listed follow-up, not an optional polish — certificate warnings train people to click through warnings, and that habit is the vulnerability.
- PBS encrypts nothing about the path here by default; the token-authenticated connection between PVE and PBS does use TLS — which is what that fingerprint check in step 4 is actually for. Take the three seconds to compare it.
- Dedicated backup user + token, one role, one datastore — nothing broader.
- Privilege separation means the token needs its own grant. The user grant alone produces a misleading 500.
- Token secret: shown once, stored in the vault, nowhere else.
Jobs, retention, and verification
This section is short because PBS makes it short — provided you put each responsibility in the one place that owns it.
The backup job lives on the PVE side: one scheduled job, all VMs, nightly (ours runs at 01:00), targeting the PBS storage, snapshot mode (guests keep running; no shutdown windows to negotiate). Mode matters: snapshot mode with a running guest is a crash-consistent-plus-agent story — for databases with strong opinions, that's a conversation to have per-workload, but for a home fleet it's the sane default.
Retention lives on the datastore, not on the job. Set the job's own retention to blank and let the datastore's prune job govern:
- Prune runs after the night's backups (04:30 in our build), keeping 14 daily / 8 weekly / 6 monthly snapshots. GFS-style retention is the difference between "we have last night" and "we have the version from before the thing that broke three weeks ago."
- Garbage collection weekly. GC reclaims chunks that pruning orphaned. Weekly is deliberate on an SMR datastore drive (see the design section); on flash you could run it more often, but weekly is rarely wrong anywhere.
- Verify weekly, with a re-verify window (30 days in our build): PBS re-reads snapshot data and checks hashes, so a chunk that went bad on disk in March is discovered by a Saturday job — not during an April restore.
- One job, all VMs, snapshot mode, nightly.
- Retention = datastore prune policy (14/8/6 starting point). Job retention blank — one owner per responsibility.
- GC weekly, verify weekly with a re-verify window: corruption should be found by a schedule, not by an incident.
The proof: back it up, restore it, boot it with the cable pulled
Everything before this section is setup. This section is the guide.
The proof backup
Pick a real VM — ideally something small but genuinely configured, not a throwaway. Trigger a manual backup from PVE to the PBS storage and watch it land in the datastore's Content view with the right size and a clean finish. That proves the write path, the token, the network, and the datastore in one motion.
The proof restore
Now restore that snapshot to a scratch VMID — a new, unused ID, never over the original — with one critical twist:
Login prompt reached = restore verified. That sentence is the entire quality bar, and it's the one most backup projects never actually clear.
Close the loop
- Enroll PBS itself in monitoring — an agent for host metrics plus uptime checks on its UI. A backup system that fails silently has failed completely; the watcher needs a watcher.
- Write down where everything lives: the datastore drive, the token's vault entry, the retention numbers, the schedule. If the documentation exists only in the builder's head, the system's bus factor is one person with a good memory.
- Name the known gap. For this build, the gap is the offsite leg: the datastore drive is one device in one building. The decided next step (an S3-backed offsite copy, with — say it with us — a pilot restore from the offsite side before it's trusted) is recorded as a build item with a date, not as a vague intention. A 3-2-1 story needs its second location; until then, say plainly in your notes that you have 3-1-0 and a plan.
The dangerous checklist
- A deduplicated backup repository where nightly restore points cost only their changed chunks — and you can state your real dedup ratio.
- A fleet-wide nightly job with retention owned in exactly one place, garbage collection matched to your disk's physics, and scheduled verification that re-reads your snapshots.
- A scoped, vault-stored token identity wiring cluster to backup server, with the privilege-separation trap already behind you.
- A backup drive that is, by itself, a recovery kit: self-describing datastore, VM configs inside the snapshots, restorable onto a single fresh node.
- A verified restore of a real VM, booted to a login prompt with its network pulled — and a scratch VM deleted afterward, leaving no doppelganger behind.
Or, in one line: your backups don't count because the job is green. They count because you restored one, on purpose, while nothing was on fire.
Build notes: PBS 4.2, Proxmox VE 9.x, three-node home cluster, datastore on a 5 TB external USB drive. Schedules and retention figures are the starting point used in this build, not commandments — size yours to your fleet and your paranoia. The offsite leg (S3) is deliberately out of scope for this guide; it gets its own build, and its own proof restore, next. Hostnames, addresses, and identifiers from the original build are omitted; every setting and schedule above is reproduced as built.