Back to blogMigration · Technical guide

    Migrate a Proxmox Backup Server with zfs send

    Move a Proxmox Backup Server datastore to a new server with zfs send, live: read-only cutover, accounts carried over with no password change, TLS fingerprint, verification.

    11 min read

    A full PBS, a server at end of life, a change of hosting provider: sooner or later, a datastore has to move. A sync job can do it, by filling a new datastore. When the datastore sits on ZFS, you can move the datastore itself, live, and suspend backups only for the time of one last incremental.

    It is the same mechanism as our offline copy with zfs send, and it is how we move a datastore from one server to another: on arrival, the Proxmox VE host reads back and decrypts its backups on the new server with the same account, the same password and the same key.

    What travels with the dataset, and what stays behind

    Travels with zfs sendStays on the old server, in /etc/proxmox-backup/
    chunks and indexes
    groups, snapshots and namespaces
    the owner of each group
    the verification state of snapshots
    the datastore declaration — datastore.cfg
    accounts — user.cfg, shadow.json, token.shadow
    permissions — acl.cfg
    jobs — prune.cfg, verification.cfg, sync.cfg
    the certificate — proxy.pem, proxy.key

    Good news for the right-hand column: a freshly installed PBS has no datastore.cfg, no acl.cfg, no token.shadow and no job files. They are created on first use. On the target, there is therefore nothing to merge with existing content: only what you created on the source needs carrying over.

    Prerequisites

    • ZFS on both sides, with the source datastore being a dataset of its own;
    • the same major PBS version, ideally with the target at least as recent;
    • the same datastore name on the target: that is the name the Proxmox VE hosts reference;
    • key-based SSH access from the target to the source — the same setup as for the offline copy.

    Step 1 — The inventory, before touching anything

    On the old PBS — keep the output
    proxmox-backup-manager version --verbose
    proxmox-backup-manager datastore show clientX
    zfs list -o name,used,avail,recordsize,atime,mountpoint rpool/datastores/clientX
    proxmox-backup-manager user list
    proxmox-backup-manager acl list
    proxmox-backup-manager prune-job list
    proxmox-backup-manager verify-job list
    proxmox-backup-manager sync-job list
    proxmox-backup-manager cert info          # the fingerprint the Proxmox VE hosts have pinned
    ls -l /etc/proxmox-backup/

    This list is what will tell you, at the end, whether anything was forgotten. On the target, prepare the parent that will receive the dataset:

    On the new PBS
    zfs create -o mountpoint=/mnt/datastore tank/datastores

    Steps 2 and 3 — Full copy, then incrementals, live

    Backups keep running on the old server throughout this phase. The datastore is not yet declared on the target: no garbage collection and no prune can touch it.

    The full copy, then as many incrementals as needed — each one shorter than the last —, are done exactly as for an offline copy: snapshot and bookmark on the old server, zfs send -L -c then zfs send -L -c -i from the bookmark, received with zfs receive -s -u (plus -x mountpoint on the first send). The commands and options are detailed in Offline copy of a PBS datastore with zfs send, steps 3 and 5; the target is simply the new PBS instead of a disk.

    From here on, the snapshots are named migration-1, migration-2… and the received dataset is tank/datastores/clientX.

    Step 4 — The cutover

    Schedule it outside the backup window: during the cutover, a backup started against the old server will fail, and that is intended.

    On the old PBS
    proxmox-backup-manager datastore update clientX --maintenance-mode type=read-only
    proxmox-backup-manager task list          # wait until no backup is still running
    
    zfs snapshot rpool/datastores/clientX@migration-final
    zfs bookmark rpool/datastores/clientX@migration-2 rpool/datastores/clientX#migration-2

    Maintenance mode does not stop what is already running

    PBS blocks new writes, but lets operations started before the mode was enabled finish. A snapshot taken right after the command may therefore contain a half-written backup. Wait for the tasks to end, and only then take the final snapshot. In read-only mode, restores remain possible throughout the cutover.

    On the new PBS
    set -o pipefail
    ssh old-pbs zfs send -L -c -i rpool/datastores/clientX#migration-2 rpool/datastores/clientX@migration-final \
      | zfs receive -s -u tank/datastores/clientX
    echo "PIPESTATUS=${PIPESTATUS[*]}"
    
    zfs mount tank/datastores/clientX        # received with -u: it is not mounted
    proxmox-backup-manager datastore create clientX /mnt/datastore/clientX --reuse-datastore true

    Expected: Access time update check successful. then TASK OK. Without the zfs mount, the mountpoint does not exist yet and datastore create hits an empty directory: the copy is not lost, it simply is not mounted.

    Step 5 — Accounts, passwords, tokens and permissions

    The owner of each group arrived with the datastore; the account bearing that name did not. As long as it does not exist on the target, the client sees nothing. And the goal is for the client to have nothing to change: no password, no token.

    The cleartext password is never needed. You carry over what PBS already stores: the password hash and the hashed token secrets. Nobody needs to know the password to perform the migration.

    The whole server moves

    The new PBS replaces the old one: take the files whole, after backing up the target's own copies.

    On the new PBS
    cd /etc/proxmox-backup
    mkdir -p /root/before-migration && cp -a user.cfg shadow.json /root/before-migration/
    
    # from the old PBS, preserving owner and permissions
    #   user.cfg  shadow.json  token.shadow  acl.cfg
    #   (+ domains.cfg and tfa.json if you use LDAP/AD or two-factor authentication)
    
    proxmox-backup-manager user list
    proxmox-backup-manager acl list

    One datastore among others moves

    If the old and new servers host other accounts, never copy the whole files: they contain everyone's accounts. Carry over four fragments, those of the one account concerned:

    The four fragments to carry over
    user.cfg      →  the "user: client@pbs" section and its lines
                   (and its "token: client@pbs!<id>" sections, if any)
    shadow.json   →  the "client" entry                 ← WITHOUT the @pbs suffix
    token.shadow  →  the "client@pbs!<id>" entry, if there are tokens
    acl.cfg       →  the line "acl:1:/datastore/clientX:client@pbs:DatastoreBackup"

    Two costly traps

    shadow.json is keyed without the realm. The entry is named client, not client@pbs. Looking it up with the suffix returns "absent" even though it exists.

    user.cfg is a section-based file, and a section with no properties must be followed by a blank line. A token: section created by generate-token often has no properties at all. Paste a section right after it, and PBS answers syntax error — then rejects the entire file: no users, no ACLs left, including for accounts that were working. Back up before editing, and check with proxmox-backup-manager user list immediately afterwards.

    Step 6 — The jobs

    Prune, verify, sync, notifications: none of these followed. Their absence does not get in the way of any restore, but a datastore without prune silently fills up — all the faster if clients, being write-only, cannot prune by themselves. Recreate them from the step 1 inventory, and leave garbage collection aside until step 8.

    Step 7 — What Proxmox VE sees: the name and the fingerprint

    Proxmox VE pins the PBS certificate fingerprint in /etc/pve/storage.cfg. A new server has a new certificate: this is the point that decides whether the migration is invisible.

    SituationWhat Proxmox VE seesTo do on the PVE side
    a front end (reverse proxy) terminates TLS in front of the PBS serversthe front end's certificate, unchangednothing
    the old PBS certificate is reused on the new one (proxy.pem + proxy.key, then restart proxmox-backup-proxy)the same certificate, hence the same fingerprintnothing, apart from the address if it changes
    new certificate, or a front end that merely passes TLS throughthe new PBS certificatepvesm set <storage> --fingerprint <fingerprint> on every PVE host

    The name: switch DNS, or change the address

    If the Proxmox VE hosts target a DNS name, point that name at the new server, and the storage configuration does not change. Once DNS has propagated, disconnecting and reconnecting the datastore on the Proxmox VE side is enough for it to reach the new server — in the web interface (Datacenter → Storage → disable, then enable again) or from the command line:

    On every Proxmox VE host, after the DNS switch
    pvesm set backup --disable 1
    pvesm set backup --disable 0
    pvesm status --storage backup

    Otherwise, change the address: pvesm set <storage> --server <new>. Either way, the fingerprint follows the rules in the table above. In the end, the storage entry differs at most by its server line — and with DNS switched, not even that one changes:

    /etc/pve/storage.cfg — before / after
    pbs: backup                              pbs: backup
        datastore clientX                        datastore clientX            ← identical
        server pbs.example.com                   server pbs.example.com       ← identical if DNS is switched
        fingerprint <fingerprint>                fingerprint <fingerprint>    ← depends on the case above
        username client@pbs                      username client@pbs          ← identical
        encryption-key <key fingerprint>         encryption-key <fingerprint> ← identical

    The client encryption key does not move: it lives on the Proxmox VE side, in /etc/pve/priv/storage/<storage>.enc, and the new PBS never sees it any more than the old one did. Declaring a second storage instead of modifying the first is also possible: that is what reactivating a datastore describes.

    Step 8 — Prove it works, before decommissioning

    Before decommissioning the old server, you need proof that you can restore from the new one: a forced verify, extracting a VM configuration (which involves the encryption key), then a real restore to a new ID. These checks are detailed, commands included, in Reactivate a PBS datastore after losing the server (steps 3 and 6). For a migration, only the order matters:

    1. the proofs: forced verify, configuration extraction, restore;
    2. only then, the first garbage collection on the new datastore;
    3. jobs re-enabled, one night of successful backups, and only then decommissioning the old server.

    Rolling back

    As long as the old server exists, you just lift the maintenance mode — proxmox-backup-manager datastore update clientX --delete maintenance-mode — and point the Proxmox VE hosts back to the old address. Nothing was destroyed on the source: snapshots and bookmarks, that is all.

    At Nimbus

    This is how we move a datastore from one of our servers to another. We carry over the password hash and the tokens: you have no new password and no new token to enter. The only point that could concern you is the fingerprint pinned in your Proxmox VE, and that is precisely what we check before moving anything.

    Frequently asked questions

    Can a PBS datastore be migrated without interrupting backups?

    Almost. The full copy and the incrementals run live, while backups keep going to the old server. The interruption is limited to the cutover: the source datastore goes into read-only maintenance, running tasks finish, then one last, short incremental goes to the new server. Restores remain possible throughout.

    Do the old and new servers need the same PBS version?

    The same major version. A target more recent than the source is not a problem. The other way round, in our test a datastore coming from PBS 4.2.5 read back on 4.2.0 caused no trouble, but that is no reason to migrate to an older release. On the ZFS side, a zfs send stream is received without difficulty on a newer OpenZFS; it is importing a disk that requires an OpenZFS aware of every active feature of the pool.

    Do users and Proxmox VE hosts have to change their password or token?

    No. The cleartext password is never needed: you carry over the hash (shadow.json) and the hashed token secrets (token.shadow), along with the account definitions (user.cfg) and their permissions (acl.cfg). Careful: shadow.json is keyed by the user name without the realm — the key is "client", not "client@pbs".

    Why does Proxmox VE refuse to connect to the new PBS?

    Most often, the certificate fingerprint. Proxmox VE pins it in /etc/pve/storage.cfg. A new server has a new certificate, hence a new fingerprint: either reuse the old server's certificate, or have a front end that terminates TLS keep presenting the same one, or update the fingerprint with pvesm set <storage> --fingerprint.

    Sync job or zfs send to migrate a PBS?

    A sync job does not require ZFS and remains the official route: it fills a new datastore snapshot by snapshot. But synced groups take the owner defined in the job (root@pam by default), which then has to be fixed for each client. zfs send moves the datastore itself, owners, namespaces and verification state included, provided you have ZFS on both sides.

    An offsite PBS you will never have to migrate

    Datastore in France, servers replaced and migrated by us, offline copy as an option. You keep your local PBS; we carry the offsite copy.