A vzdump wrapper script with checks, retention and a log file
A Bash wrapper around vzdump that checks the target storage first, backs up chosen guests or all guests with zstd and keep-last retention, writes a log and lists failed guests.
Scheduled backup jobs in the web UI cover most needs. A small wrapper is still useful for ad-hoc runs before maintenance, for cron on standalone nodes, or as a building block for your own automation. This script validates its input, confirms the target storage is active through the API, runs vzdump with consistent options and keeps a log per run.
What it does
- Checks arguments, that it runs as root, and that
vzdumpandpveshexist. - Reads
/nodes/<node>/storage/<id>/statusand stops if the storage is missing or not active. - Runs
vzdumpin snapshot mode (or the mode you pass) with--compress zstd,--prune-backups keep-last=Nand a notes template. - Saves output to
/var/log/pve-backup-wrapper/, returns vzdump’s exit code and prints lines for failed guests.
Script
#!/usr/bin/env bash
# pve-backup.sh - run vzdump for selected guests with sane defaults and a log
# License: CC0-1.0
# Usage: pve-backup.sh -s STORAGE [-k KEEP_LAST] [-m MODE] (-a | VMID...)
# -s target storage ID (must allow the "backup" content type)
# -k how many backups per guest to keep on that storage (default 7)
# -m snapshot | suspend | stop (default snapshot)
# -a back up all guests on this node
set -euo pipefail
storage=""
keep_last=7
mode="snapshot"
all=0
log_dir="/var/log/pve-backup-wrapper"
usage() {
echo "Usage: $0 -s STORAGE [-k KEEP_LAST] [-m snapshot|suspend|stop] (-a | VMID...)" >&2
exit 2
}
while getopts ":s:k:m:a" opt; do
case "$opt" in
s) storage="$OPTARG" ;;
k) keep_last="$OPTARG" ;;
m) mode="$OPTARG" ;;
a) all=1 ;;
*) usage ;;
esac
done
shift $((OPTIND - 1))
[ -n "$storage" ] || usage
[[ "$keep_last" =~ ^[1-9][0-9]*$ ]] || { echo "Error: -k must be a positive number" >&2; exit 2; }
case "$mode" in snapshot|suspend|stop) ;; *) usage ;; esac
if [ "$all" -eq 0 ] && [ "$#" -eq 0 ]; then usage; fi
for id in "$@"; do
[[ "$id" =~ ^[0-9]+$ ]] || { echo "Error: '$id' is not a VMID" >&2; exit 2; }
done
if [ "$(id -u)" -ne 0 ]; then
echo "Error: run as root on a Proxmox VE node." >&2
exit 1
fi
for cmd in vzdump pvesh; do
command -v "$cmd" >/dev/null 2>&1 || { echo "Error: '$cmd' not found - is this a Proxmox VE node?" >&2; exit 1; }
done
node=$(hostname)
status_json=$(pvesh get "/nodes/$node/storage/$storage/status" --output-format json 2>/dev/null) || {
echo "Error: storage '$storage' not found on node '$node'." >&2
exit 1
}
if ! grep -Eq '"active"[[:space:]]*:[[:space:]]*1' <<<"$status_json"; then
echo "Error: storage '$storage' is not active on node '$node'." >&2
exit 1
fi
mkdir -p "$log_dir"
log_file="$log_dir/backup-$(date +%Y%m%d-%H%M%S).log"
args=(--storage "$storage" --mode "$mode" --compress zstd
--prune-backups "keep-last=$keep_last"
--notes-template '{{guestname}} on {{node}}')
if [ "$all" -eq 1 ]; then
args+=(--all 1)
targets="all guests"
else
targets="$*"
fi
echo "Backing up $targets to '$storage' (mode=$mode, keep-last=$keep_last)"
echo "Log: $log_file"
set +e
if [ "$all" -eq 1 ]; then
vzdump "${args[@]}" 2>&1 | tee "$log_file"
else
vzdump "$@" "${args[@]}" 2>&1 | tee "$log_file"
fi
rc=${PIPESTATUS[0]}
set -e
if [ "$rc" -eq 0 ]; then
echo "Backup finished successfully."
else
echo "Backup finished with errors (exit code $rc). Failed guests:" >&2
grep -E '^ERROR: Backup of VM [0-9]+ failed' "$log_file" >&2 || echo " see $log_file" >&2
fi
exit "$rc"
Usage
chmod +x pve-backup.sh
./pve-backup.sh -s nas-backup 110 111
./pve-backup.sh -s nas-backup -k 14 -a
./pve-backup.sh -s nas-backup -m stop 200
Example cron entry for a nightly run at 01:30 on a standalone node (/etc/cron.d/pve-backup):
30 1 * * * root /usr/local/sbin/pve-backup.sh -s nas-backup -k 7 -a
Notes
--prune-backups keep-last=Ndeletes older backups of each guest on that storage beyond N. If the storage already has a retention policy you rely on, adjust or remove that option so the two do not conflict.- The node name is taken from
hostname, which matches the Proxmox VE node name on a standard install. - In a cluster, prefer a backup job under Datacenter → Backup: it runs on every node and is visible to all administrators.
- Test a restore of the resulting files regularly.
Official documentation
See also
- 0058 Safe bash script template with set ‑euo pipefail and trap A starting point for bash scripts that stops on errors, rejects unset variables, cleans up temp files on exit and parses options.… Intermediate · Reference · Linux, macOS Script Shell scripting 15 Oct 2026
- 0059 Incremental snapshot backups with rsync A bash script that copies a folder into dated snapshots with rsync, hard-links unchanged files to the previous snapshot to save space,… Advanced · How-to · Linux, macOS Script Backups & syncing · Shell scripting 15 Oct 2026
- 0061 Fix: Address already in use (free a busy port) Your server cannot start because another process already listens on its port. This script shows which process holds the port and stops… Intermediate · Fix · Linux, macOS Script Processes & ports · Shell scripting 15 Oct 2026
- 0106 Back up and restore guests with vzdump, backup jobs and Proxmox Backup Server Back up Proxmox VE VMs and containers with vzdump, choose a backup mode, schedule backup jobs with retention, restore with qmrestore or… Intermediate · How-to · Linux Article Backup & restore 15 Oct 2026
- 0108 List all Proxmox VE guests with status and locks (pvesh + jq) A Bash script that lists every VM and container in the cluster with node, status, lock, memory and uptime, using the Proxmox… Intermediate · Reference · Linux Script Shell scripting · VMs & containers 15 Oct 2026
- 0110 Fix: TASK ERROR: VM is locked (backup) A VM or container still carries a backup lock, usually after a backup was interrupted. Check that no backup is running, then… Beginner · Fix · Linux Article Backup & restore · VMs & containers 15 Oct 2026
History
Every saved edit is kept. The plot on the sleeve draws one line per edit. Open any edit to see exactly what changed.
- commitpedia-admin +5,007 chars