Summary
Rolled out automated monthly backups of Proxmox VE host configuration to a centralized SMB share across a multi-node cluster. Bash script in cron.monthly, tar.gz archives of the directories that actually matter when a host dies, 6 archives of retention per directory, automatic cleanup. Because if you can't rebuild the host, you can't restore the VMs running on it.
The challenge
Proxmox has excellent built-in backup for VMs and containers. Host-level config is the part everyone forgets until a node dies and they're staring at a fresh install trying to remember whether the bond was LACP or active-backup, or what the SMB credentials for the backup NAS were. The stuff you actually need to rebuild a Proxmox host includes:
- network config — bridges, bonds, VLANs
- custom scripts and tooling in /root and /opt
- cluster certificates and membership data
- storage mount points and their credentials
- any /etc customizations — sysctl tweaks, systemd units, cron entries
Without host-level backups, rebuilding a failed node means reconstructing all of that from memory or from documentation that's probably out of date. Neither is fast, neither is reliable, and both happen at 2 AM.
Solution architecture
Bash script in /etc/cron.monthly/ runs on the first of every month, tars up the critical directories into timestamped archives, and drops them on an SMB share. Old archives get pruned automatically so storage stays bounded.
- monthly execution via cron.monthly
- central SMB share reachable by every Proxmox host
- timestamped archives for point-in-time recovery
- keep the last 6 per directory, delete the rest
- logs everything to /var/log/proxmox_config_backup.log
- pre-flight check bails out if the SMB share isn't mounted instead of silently dumping backups to local disk
Directories backed up
- /etc — network config, storage mounts, services, sysctl, systemd, everything else
- /root — admin home: custom scripts, SSH keys, tooling
- /opt — third-party: monitoring agents, custom apps
- /var/lib/pve-cluster — cluster database: VM configs, resource pools, user permissions, datacenter settings, cluster membership
The script
Placed in /etc/cron.monthly/ so cron runs it on the first of each month without anything extra in crontab.
#!/bin/bash
# Define backup location (Proxmox SMB mount point)
SMB_FOLDER="/mnt/pve/proxmox_hosts"
LOG_FILE="/var/log/proxmox_config_backup.log"
TIMESTAMP=$(date +'%Y-%m-%d_%I-%M-%S%p')
HOSTNAME=$(hostname)
# Directories to back up (Absolute Paths)
DIRS_TO_BACKUP=(
"/etc"
"/root"
"/opt"
"/var/lib/pve-cluster"
)
# Ensure SMB mount is available before proceeding
if ! mount | grep -q "$SMB_FOLDER"; then
echo "$(date +'%Y-%m-%d %H:%M:%S') - ERROR: SMB Share ${SMB_FOLDER} not mounted!" | tee -a "${LOG_FILE}"
exit 1
fi
echo "$(date +'%Y-%m-%d %H:%M:%S') - Starting Proxmox config backup for ${HOSTNAME}..." | tee -a "${LOG_FILE}"
# Backup each directory
for dir in "${DIRS_TO_BACKUP[@]}"; do
if [ -d "$dir" ]; then
BACKUP_FILE="${SMB_FOLDER}/${HOSTNAME}_$(basename $dir)_${TIMESTAMP}.tgz"
echo "$(date +'%Y-%m-%d %H:%M:%S') - Backing up ${dir} to ${BACKUP_FILE}" | tee -a "${LOG_FILE}"
tar --ignore-failed-read -czf "${BACKUP_FILE}" "${dir}" \
&& echo "$(date +'%Y-%m-%d %H:%M:%S') - Backup successful: ${BACKUP_FILE}" | tee -a "${LOG_FILE}" \
|| echo "$(date +'%Y-%m-%d %H:%M:%S') - ERROR: Failed to backup ${dir}" | tee -a "${LOG_FILE}"
else
echo "$(date +'%Y-%m-%d %H:%M:%S') - INFO: Skipping ${dir} (not found)" | tee -a "${LOG_FILE}"
fi
done
# Cleanup: Keep only the last 6 backups per directory
echo "$(date +'%Y-%m-%d %H:%M:%S') - Cleaning up old backups..." | tee -a "${LOG_FILE}"
for dir in "${DIRS_TO_BACKUP[@]}"; do
BACKUP_PREFIX="${SMB_FOLDER}/${HOSTNAME}_$(basename $dir)_"
ls -t ${BACKUP_PREFIX}*.tgz | tail -n +7 | xargs rm -f 2>/dev/null
echo "$(date +'%Y-%m-%d %H:%M:%S') - Cleanup done for ${dir}" | tee -a "${LOG_FILE}"
done
echo "$(date +'%Y-%m-%d %H:%M:%S') - Backup completed successfully for ${HOSTNAME}." | tee -a "${LOG_FILE}"Key bits:
- pre-flight check: if the SMB share isn't mounted, it logs an error and exits instead of silently dumping backups to local disk
- --ignore-failed-read: keeps tar going if it hits something it can't read (open files, sockets) instead of aborting the whole archive
- cleanup loop uses ls -t | tail -n +7 to keep the 6 most recent per directory and delete the rest
File naming
Format is {hostname}{directory}{timestamp}.tgz. From a single host you end up with:
- proxmox01_etc_2025-01-28_11-06-13PM.tgz
- proxmox01_root_2025-01-28_11-06-13PM.tgz
- proxmox01_opt_2025-01-28_11-06-13PM.tgz
- proxmox01_pve-cluster_2025-01-28_11-06-13PM.tgz
Implementation steps
- Mount the SMB share persistently. Add to /etc/fstab with a credentials file (not a plaintext password in the fstab line). Create /root/.smbcredentials with permissions 600 containing username/password, then reference it with credentials=/root/.smbcredentials. Verify with ls /mnt/pve/proxmox_hosts.
- Drop the script in /etc/cron.monthly/proxmox_config_to_nas and chmod +x it.
- Run it manually once. Confirm archives appear on the share and /var/log/proxmox_config_backup.log shows the expected output.
- If scripts in cron.monthly aren't firing on your install (it happens), add an explicit crontab entry: 0 2 1 * * root /etc/cron.monthly/proxmox_config_to_nas >/dev/null 2>&1, then systemctl restart cron.
Multi-host deployment
The script uses $(hostname) everywhere the hostname appears, so it's host-agnostic. Deploy the exact same file to every Proxmox node — backups land on the shared SMB target already namespaced by hostname, retention is managed per host, and nothing needs per-node customization.
Outcome
Every host in the cluster gets its config snapshotted monthly, with six months of retention, to one SMB share. Zero ongoing maintenance. If we lose a node, the rebuild path is: install Proxmox, restore /etc, /root, /opt, and /var/lib/pve-cluster from the latest archive, rejoin the cluster. The VMs — already backed up by Proxmox's built-in tooling — land back on the rebuilt host and come up.
- zero ongoing maintenance, once per month log check in monitoring
- rapid rebuild capability covering everything the Proxmox installer doesn't
- same script across the cluster, no per-host customization
- timestamped archives give you an audit trail and the ability to roll back a config change