← Back to Wiki
Proxmox / Backups

Set Up Proxmox Backup Server

Proxmox Backup Server (PBS) gives your Proxmox VE fleet real deduplicated, incremental backups — but the NFS storage setup has a permissions gotcha that trips up almost everyone the first time.

The setup

PBS runs happily as its own VM. Point it at NFS-backed storage from a NAS for the actual backup datastore:

mkdir -p /mnt/pbs-backups
mount -t nfs <nas-ip>:/volume1/pbs-backups /mnt/pbs-backups
echo "<nas-ip>:/volume1/pbs-backups /mnt/pbs-backups nfs defaults,_netdev,vers=4.1 0 0" >> /etc/fstab
Gotcha: PBS refuses to initialize a datastore in a non-empty directory, and many NAS vendors automatically create a hidden recycle-bin folder at the share root. Point the datastore at a clean subdirectory instead of the share root:
mkdir -p /mnt/pbs-backups/datastore

The NFS permission gotcha (the one that gets everyone)

PBS needs to write to the datastore as root to build its internal structure. Most NAS NFS export rules default to "root squash" — mapping the remote root user down to an unprivileged account, which silently blocks exactly this. Set the NFS permission rule for PBS's IP explicitly to Read/Write, squash: No mapping. Even with that rule set correctly, the first backup run can still fail with a permission error if the actual directory permissions on the share are still restrictive — if so, fix them directly on the NAS itself, not through the NFS client:
ssh <nas>
sudo chmod -R 777 /volume1/pbs-backups

Connecting PBS to your hypervisor

This needs a token/ACL setup on both sides:

  1. On PBS: create an API token (Configuration → Access Control → API Tokens) and grant it the datastore admin role:
    proxmox-backup-manager acl update /datastore/<name> DatastoreAdmin --auth-id 'root@pam!<token-name>'
  2. On your hypervisor: add PBS as a storage target, using the user@realm!tokenname format for the username field and the token secret (not the token name) as the password.
If storage registration fails with 401 Unauthorized, check the username field includes the !tokenname suffix. If it then fails with "cannot find datastore," check proxmox-backup-manager acl list on PBS — a token can authenticate successfully while still having zero actual permissions on anything, which produces exactly this error.

Backup job configuration

A reasonable starting retention policy: keep-last 3, keep-daily 7, keep-weekly 4, keep-monthly 2, keep-yearly 1. Note that many backup job configurations use an explicit VM/container ID list, not "all" — meaning every new VM or container needs to be added to the job by hand. This is an easy thing to forget when spinning up new infrastructure; worth a periodic audit to catch anything that slipped through.

Sizing your NAS storage realistically

Don't trust df on a shared NFS mount to estimate actual backup datastore size. df reports usage for the entire underlying volume, which may be shared by many unrelated exports on the same NAS. Use du -sh on the actual exported path instead to get the real number — the difference can be enormous (one real case: df showed 23TB, the actual datastore was 185GB).

Migrating the datastore to new storage later

If you ever need to move the backing storage to a different NAS, the safe sequence is: mount the new share alongside the old one, rsync the datastore across, verify file counts and sizes match on both sides, then cut over. Cutover itself needs the PBS services stopped first — the daemon holds a lock file open on the datastore, so unmounting fails with "device busy" while it's running. Update the mount config to point at the new location, remount at the same path, and restart the services. If the datastore name and mount path don't change, no hypervisor-side configuration needs updating at all — it only talks to PBS's API, never the NAS directly.

Gotcha: if a migration script combines a potentially-failing command (like an unmount) with a config-file edit in one block under set -e, a failure in the first command silently skips the edit entirely — the script just exits. Don't rely on strict-mode ordering when chaining a command that might fail with one that absolutely must run regardless; check exit codes explicitly instead.

Don't forget to actually retire the old copy

It's tempting to leave the old storage location as a permanent safety net after a migration, but "temporary rollback copy" has a way of quietly becoming permanent clutter. Once the new storage has a genuine track record — several days of successful backups and verification/garbage-collection jobs, not just "the cutover didn't immediately explode" — retire the old copy deliberately rather than leaving it indefinitely:

Gotcha: a "dedicated direct link" network (a 10G point-to-point connection between your hypervisor and NAS, for example) is often genuinely unreachable from anywhere except the two ends of that link — trying to reach it from a third machine (your workstation, say) can time out in a way that looks like a transient network hiccup but is actually working exactly as designed. If a host has two addresses (a fast dedicated link and a normal LAN address), use the normal LAN address for anything that isn't the hypervisor itself.

Backing up a physical Windows PC (not just VMs)

PBS isn't limited to backing up VMs and containers — a real, physical Windows machine can back up to the same datastore. The catch: Proxmox doesn't actually ship an official Windows client. The real option is a third-party, alpha-quality community reimplementation of the backup protocol, distributed as two small executables — one for folder-level backups, one for whole-disk image backups. Both are unsigned, so expect Windows Defender to flag or slow them down, and treat "alpha quality" as a literal warning, not just a disclaimer.

Gotcha: a PowerShell script launched by double-clicking closes itself the instant the process exits or crashes — taking any error output with it. A folder-level backup run crashed silently partway through and looked like a normal, boring exit; only checking the actual datastore afterward (and finding a corrupted, incomplete snapshot) revealed anything had gone wrong. Two fixes: always launch from an already-open terminal rather than double-clicking, and have the script pause for input at the very end (success or failure) so a double-click launch can't hide a crash behind a closing window.

For anything where "don't lose a single file" actually matters more than "back up efficiently," a full-disk image (capturing the whole drive via a live snapshot) is the safer default over picking specific folders — it doesn't depend on remembering every folder that matters, and it survives a folder-level tool's rougher edges.

The permission bug that looks exactly like a config error

An API token's real permissions can be the *intersection* of two separate grants, not just its own. Some backup/virtualization platforms let you grant a role directly to a token and separately to its parent user account — and the token's actual effective access is whichever permissions both of them agree on. Granting a role only to the token, while its parent user has none, produces a token that authenticates fine but can do nothing — every request gets rejected, and a simple "list this token's granted roles" check looks completely correct the whole time, because it only shows what was granted, not what's actually effective. If a freshly-permissioned token still gets rejected and the ACL looks right, check whether the platform has this two-sided model before assuming the credential itself is wrong — grant the same role to both the token and its parent account.

Scaling this to a whole household

Once more than one physical machine needs this, a few small pieces of infrastructure make it repeatable instead of a manual one-off each time: