Files
scripts/proxmox-backup
2026-07-13 00:48:28 -04:00
..
2026-07-13 00:48:28 -04:00
2026-07-13 00:48:28 -04:00

Proxmox VE Backup & Restore Tool

A self-contained bash script for backing up and restoring all critical Proxmox VE configuration files. Archives are stored locally (never on the remote host) and can be used to rebuild a PVE node after boot drive failure.

Overview

The script connects to a Proxmox node (locally or over SSH), collects configuration files from across the filesystem, packages them into a timestamped .tar.gz archive, and stores it on the machine running the script. Restore extracts a backup archive and pushes files back.

Requirements

  • Source node: Proxmox VE (any supported version)
  • Machine running the script: Linux with bash, tar, gzip
  • Remote access: SSH access to the Proxmox node (passwordless key recommended)
  • Permissions: Root or passwordless sudo on the Proxmox node
  • rsync (optional): Installed on both machines for incremental transfers — falls back to tar/cat/pipe if absent

Usage

Usage: pve-backup.sh <command> [options]

Commands:
  backup        Create a backup of Proxmox configuration
  restore       Restore Proxmox configuration from a backup
  list          List available backups
  verify        Verify a backup archive's integrity (SHA256)

Backup options:
  -d, --dir DIR         Local backup directory (default: ./pve-backups)
  -h, --host HOST       Remote Proxmox host (SSH)
  -u, --user USER       SSH user (default: root)
  -i, --identity FILE   SSH identity file

Restore / Verify options:
  -d, --dir DIR         Directory containing backup archive
  -f, --file FILE       Specific backup archive to restore/verify
  -y, --yes             Skip confirmation prompts (DANGEROUS)

List options:
  -d, --dir DIR         Directory to list backups from

Examples

# Local backup (must be root on the Proxmox node)
./pve-backup.sh backup

# Remote backup with custom directory
./pve-backup.sh backup -h 192.168.1.100 -d /mnt/backups

# Remote backup as non-root user (uses sudo -n automatically)
./pve-backup.sh backup -h 192.168.1.100 -u admin -i ~/.ssh/id_rsa

# Verify a backup archive
./pve-backup.sh verify -f pve-backups/pve-backup-prox1-20250101_120000.tar.gz

# Restore the latest backup
./pve-backup.sh restore

# Restore a specific backup archive
./pve-backup.sh restore -f /path/to/pve-backup-prox1-20250101_120000.tar.gz

# Non-interactive restore (for automation)
./pve-backup.sh restore -f /path/to/backup.tar.gz -y

# List all local backups
./pve-backup.sh list

Defaults

Setting Default
Backup directory ./pve-backups (relative to script location)
SSH user root
Archive name format pve-backup-{hostname}-{YYYYMMDD}_{HHMMSS}.tar.gz

Transfer Method

The script uses one of two transfer methods depending on what's available:

rsync (preferred)

When connecting to a remote host, the script checks if rsync is installed on the remote side. If yes:

  • File-based configs (/etc/pve/, /etc/network/interfaces, APT sources, etc.) are transferred via rsync -a
  • Subsequent backups only transfer changed files, reducing bandwidth and time
  • Permissions and ownership are preserved natively by rsync
  • If sudo is needed, --rsync-path="sudo -n rsync" is used automatically

tar/cat/pipe (fallback)

If rsync is not available on the remote host, the script falls back to the original method:

  • /etc/pve/ is tarballed on the remote, piped through SSH, and extracted locally
  • Individual files are fetched with cat > file over SSH
  • Directories (APT sources, sysctl, cron) are tarballed with cp -a, then piped through SSH
  • Slightly slower on repeated runs since everything is transferred every time

What Gets Backed Up

/etc/pve/ (pmxcfs snapshot)

The core Proxmox cluster filesystem. Transferred via rsync -a when available, otherwise tarballed and piped over SSH. Either way, runtime-only data is excluded:

Included Description
datacenter.cfg Datacenter-wide settings
storage.cfg Storage pool definitions
user.cfg Users, groups, and permissions
domains.cfg Authentication realms (LDAP, AD, etc.)
vzdump.cfg Default backup job settings
nodes/{node}/qemu-server/*.conf VM configuration files
nodes/{node}/lxc/*.conf LXC container configuration files
nodes/{node}/pve-ssl.pem Web UI SSL certificate
nodes/{node}/pve-ssl.key Web UI SSL private key
nodes/{node}/pveproxy-ssl.pem Custom SSL certificate (if set)
nodes/{node}/pveproxy-ssl.key Custom SSL private key (if set)
sdn/ Software Defined Network configs (VLANs, VNets, subnets)
ha/ High Availability resources and groups
firewall/ Datacenter and node-level firewall rules
priv/tfa.cfg TFA tokens (restore with caution)
priv/shadow User password hashes
Excluded Reason
.rrd/ Round-robin database (runtime stats, regenerated)
priv/known_hosts SSH host keys (regenerated on boot)
*.lock Runtime locks (ephemeral)

Network Configuration

File Description
/etc/network/interfaces Bridge, bond, VLAN, and NIC definitions
/etc/hostname System hostname
/etc/hosts Static hostname resolution
/etc/fstab Filesystem mount table (ZFS, NFS, CIFS mounts, etc.)
/etc/resolv.conf DNS nameservers and search domains

APT Sources

Path Description
/etc/apt/sources.list Main APT repository list
/etc/apt/sources.list.d/ Third-party and Proxmox enterprise/no-subscription repos
/etc/apt/auth.conf APT authentication credentials

Cluster Configuration

File Description
/etc/corosync/corosync.conf Corosync cluster ring and membership config

Ceph Storage

File Description
/etc/ceph/ceph.conf Ceph cluster connection settings

System Tuning

Path Description
/etc/sysctl.d/ Kernel parameter overrides (network buffers, etc.)
/etc/cron.d/ System cron jobs
/etc/cron.daily/ Daily cron scripts

Package Manifest

File Contents
packages.txt Full list of installed packages (dpkg-query -W)
packages-manual.txt Manually installed packages (apt-mark showmanual)
pveversion.txt Proxmox VE version string

Firewall Rules

File Description
iptables.rules IPv4 iptables ruleset (via iptables-save)
ip6tables.rules IPv6 ip6tables ruleset (via ip6tables-save)

Metadata (META file inside archive)

hostname:   proxmox1
created:    2025-01-01T12:00:00Z
pveversion: pve-manager/8.2.4/123456789abc
pve_nodes:  proxmox1 proxmox2 proxmox3

Restore Process

  1. Extracts the backup archive to a temporary directory
  2. Creates a rollback snapshot of the current /etc/pve at /var/tmp/pve-restore-rollback-{timestamp}/ (and also a tarball at /etc/pve-rollback.tar.gz on the remote node)
  3. Restores /etc/pve by piping the archived tarball into tar -x -C /etc/pve on the target node
  4. Restores network configs (/etc/network/interfaces, hostname, hosts, resolv.conf) by piping each file through SSH
  5. Restores APT sources, sysctl, and cron overrides
  6. Does not restore the package manifest — this is for reference only

After restore:

  • Reboot recommended — network and hostname changes apply at boot
  • Restart pveproxy if the web UI behaves oddly after /etc/pve restore

SSH Non-Root Access (sudo)

If you connect with a non-root SSH user (-u admin), the script automatically detects this and prefixes all remote commands with sudo -n. The remote user must have passwordless sudo configured:

echo "admin ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers.d/admin

If passwordless sudo is not available, the script exits with a clear error.

Archive Format

Each backup is a gzipped tarball with this internal structure. The /etc/pve/ data and sysconfig may be stored either as raw directories (when rsync was used) or as nested tarballs (when the fallback method was used):

pve-backup-proxmox1-20250101_120000.tar.gz
├── META                          # Metadata (hostname, date, version, nodes)
└── etc/
    ├── pve/
    │   ├── datacenter.cfg        # (raw files — rsync) or
    │   └── pve-config.tar.gz     # (nested tarball — fallback)
    ├── apt/
    │   ├── sources.list          # (raw files — rsync) or
    │   └── apt-sources.tar.gz    # (nested tarball — fallback)
    └── system/
        ├── interfaces            # /etc/network/interfaces
        ├── hostname              # /etc/hostname
        ├── hosts                 # /etc/hosts
        ├── resolv.conf           # /etc/resolv.conf
        ├── fstab                 # /etc/fstab
        ├── corosync.conf         # /etc/corosync/corosync.conf
        ├── ceph.conf             # /etc/ceph/ceph.conf
        ├── sysctl.d/             # (raw dir — rsync) or
        ├── sysconfig.tar.gz      # (nested tarball — fallback)
        ├── packages.txt          # Full package manifest
        ├── packages-manual.txt   # Manually installed packages
        ├── pveversion.txt        # pveversion output
        ├── iptables.rules        # iptables-save output
        └── ip6tables.rules       # ip6tables-save output

The restore logic handles both layouts transparently.

Verification

Every backup automatically generates a .sha256 checksum file alongside the archive. You can verify integrity at any time:

# Verify the latest backup
./pve-backup.sh verify -f pve-backups/pve-backup-prox1-20250101_120000.tar.gz

The verify command checks:

  1. The archive is a valid gzip'd tar file (no corruption)
  2. The SHA256 checksum matches the stored .sha256 file (no tampering)

If no .sha256 file exists (e.g., from older backups), one is generated on the spot.

Security Notes

  • Backup over SSH: All data is transferred over the encrypted SSH channel. No data is stored on the remote host.
  • Sensitive data: The archive contains SSL private keys, password hashes (/etc/pve/priv/shadow), and TFA tokens. Treat backup archives as sensitive credentials.
  • SSH keys: Use -i to specify an SSH identity file. Agent forwarding is not required.

Limitations

  • Package manifest is for reference only — the script does not install/restore packages
  • Firewall rules are exported via iptables-save — restoration requires manual iptables-restore (PVE firewall is handled via /etc/pve/firewall/ in the pve-config archive)
  • Ceph config is backed up, but the Ceph monitor maps and OSD tree are not
  • VM/CT disk images and backups are not included — use the built-in Proxmox Backup Server or vzdump for those

Future Enhancements (not yet implemented)

These are left as exercises for the reader or future development:

  • Retention / rotation--keep N flag to auto-prune backups older than N days (or keep only N most recent)
  • Cron / systemd timer — drop-in unit for daily automated backups
  • Encryption — GPG or age encrypt the archive before writing it to disk, decrypt on restore
  • Email / notification — alert on backup failure or successful completion
  • Restore dry-run — show what would be restored without actually pushing files