Proxmox Backup Strategy: Git + HDD + Google Drive
May 30, 2026Tutorials
A complete walkthrough for setting up automated, multi-layered backups for your Proxmox home server — config files to GitHub, LXC snapshots to HDD, and offsite copies to Google Drive.
![]()
Running a home server is great until something breaks and you realize you never backed it up. This guide walks through a complete, three-layer backup strategy for a Proxmox host running LXC containers:
- Git backup — Proxmox config files versioned on a private GitHub repo
- HDD backup — Full LXC container snapshots stored on a local HDD
- GDrive offsite — Latest backup per container synced to Google Drive
Everything is automated via cron and designed to survive a full Proxmox reinstall.
System Reference
| Property | Value |
|---|---|
| Proxmox host IP | 192.168.0.150 |
| SSH user | root |
| HDD mount path | /mnt/hdd |
| Backup storage path | /mnt/hdd/proxmox-backups |
Containers in scope
| VMID | Name | Backup Type |
|---|---|---|
| 151 | img-server | Automated (weekly) |
| 152 | caddy | Automated (weekly) |
| 153 | jellyfin | Automated (weekly) |
| 154 | uptimekuma | Automated (weekly) |
| 155 | forge | Manual one-time only |
| 156 | nexus | Manual one-time only |
Containers 155 and 156 are stopped and only need a one-time snapshot — they won't be part of the automated schedule.
Part 1 — Git Backup of Config Files
What we're backing up and why
Proxmox stores all of its configuration — VM/LXC definitions, storage, network, users — under /etc/pve/ and a few other /etc/ files. These are plain text files, which makes them perfect for version control.
The idea here is simple: copy these files into a local git repo, commit any changes, and push to a private GitHub repo. If your host ever dies or you reinstall Proxmox, you can pull this repo and have your entire config back in seconds.
Files we track:
/etc/pve/— all Proxmox configs (LXC configs, storage definitions, cluster state)/etc/network/interfaces— network bridge/VLAN config/etc/hosts/etc/hostname
Step 1.1 — SSH in and install Git
ssh root@192.168.0.150
apt update && apt install git -yThen set your git identity:
git config --global user.name "Your Name"
git config --global user.email "your@email.com"Step 1.2 — Generate an SSH key for GitHub
We'll create a dedicated SSH key for this backup job rather than reusing any existing key. This keeps things clean and lets you revoke it independently if needed.
ssh-keygen -t ed25519 -C "proxmox-backup" -f ~/.ssh/github_backup -N ""
cat ~/.ssh/github_backup.pubCopy the output and add it to your GitHub account: GitHub → Settings → SSH and GPG Keys → New SSH Key
Now configure SSH on the Proxmox host to use this key for GitHub:
cat >> ~/.ssh/config << 'EOF'
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/github_backup
IdentitiesOnly yes
EOF
chmod 600 ~/.ssh/configTest it:
ssh -T git@github.comExpected output:
Hi seemantshekhar43! You've successfully authenticated, but GitHub does not provide shell access.Step 1.3 — Initialize the local config repo
Create the directory that will hold our backed-up configs, initialize a git repo, and point it at your GitHub remote. Create the private GitHub repo first if you haven't already (e.g. homelab-config-backup).
mkdir -p /opt/homelab-config-backup
cd /opt/homelab-config-backup
git init
git remote add origin git@github.com:YOUR_GITHUB_USERNAME/homelab-config-backup.gitAdd a .gitignore to make sure private keys and certificates don't get committed:
cat > .gitignore << 'EOF'
*.key
*.pem
authkey
priv/
EOFStep 1.4 — Create the backup script
This script copies the config files into the repo, stages everything, and only commits + pushes if something actually changed. That way you don't end up with empty commits polluting the history.
cat > /usr/local/bin/git-config-backup.sh << 'EOF'
#!/bin/bash
REPO_DIR="/opt/homelab-config-backup"
LOG="/var/log/git-config-backup.log"
DATE=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$DATE] Starting config backup" >> $LOG
# Copy configs into repo
cp -r /etc/pve "$REPO_DIR/"
cp /etc/network/interfaces "$REPO_DIR/"
cp /etc/hosts "$REPO_DIR/"
cp /etc/hostname "$REPO_DIR/"
# Copy scripts into repo
cp /usr/local/bin/git-config-backup.sh "$REPO_DIR/scripts/"
cp /usr/local/bin/lxc-backup.sh "$REPO_DIR/scripts/"
cp /usr/local/bin/gdrive-sync.sh "$REPO_DIR/scripts/"
cd "$REPO_DIR"
git add -A
# Only commit if there are changes
if git diff --cached --quiet; then
echo "[$DATE] No changes to commit" >> $LOG
else
git commit -m "config backup: $DATE"
git push origin main >> $LOG 2>&1
echo "[$DATE] Pushed to GitHub successfully" >> $LOG
fi
EOF
chmod +x /usr/local/bin/git-config-backup.shStep 1.5 — Do the initial push
cd /opt/homelab-config-backup
git add -A
git commit -m "initial config backup"
git branch -M main
git push -u origin mainNote: If you initialized git and your branch is called
master, thegit branch -M mainrenames it. You can skip this if your repo is already onmain.
Part 2 — LXC Backups to Local HDD
What we're doing here
vzdump is Proxmox's built-in backup tool. It can snapshot a running container (using the snapshot mode) and write a compressed archive to a storage target. We're going to register our HDD as a Proxmox storage backend, then write a script that dumps LXCs 151–154 to it weekly, keeping the two most recent backups per container.
Step 2.1 — Register the HDD as a backup storage target
First, add the HDD directory to Proxmox's storage config and create the dump subdirectory (Proxmox writes backups there by convention):
pvesm add dir hdd-backup --path /mnt/hdd/proxmox-backups --content backup
mkdir -p /mnt/hdd/proxmox-backups/dumpYou can verify it appeared in the Proxmox web UI under Datacenter → Storage.
Step 2.2 — Create the LXC backup script
The script loops over each container ID, runs vzdump, then prunes old backups so only the two most recent archives per VMID are kept. The --mode snapshot flag means the container doesn't need to be stopped.
cat > /usr/local/bin/lxc-backup.sh << 'EOF'
#!/bin/bash
STORAGE="hdd-backup"
BACKUP_DIR="/mnt/hdd/proxmox-backups/dump"
LOG="/var/log/lxc-backup.log"
DATE=$(date '+%Y-%m-%d %H:%M:%S')
VMIDS="151 152 153 154"
KEEP=2
echo "[$DATE] Starting LXC backup" >> $LOG
for VMID in $VMIDS; do
echo "[$DATE] Backing up VMID $VMID" >> $LOG
vzdump $VMID \
--storage $STORAGE \
--mode snapshot \
--compress zstd \
--quiet 1 >> $LOG 2>&1
if [ $? -eq 0 ]; then
echo "[$DATE] VMID $VMID backup complete" >> $LOG
else
echo "[$DATE] ERROR: VMID $VMID backup failed" >> $LOG
fi
# Prune old backups — keep only last $KEEP for this VMID
ls -t "$BACKUP_DIR"/vzdump-lxc-${VMID}-*.tar.zst 2>/dev/null | \
tail -n +$((KEEP + 1)) | \
xargs -r rm -v >> $LOG 2>&1
done
echo "[$DATE] LXC backup complete" >> $LOG
EOF
chmod +x /usr/local/bin/lxc-backup.shStep 2.3 — Manual one-time backup for stopped containers
For VMIDs 155 and 156 (which are stopped), we use --mode stop instead of snapshot. Run these once manually:
vzdump 155 --storage hdd-backup --mode stop --compress zstd
vzdump 156 --storage hdd-backup --mode stop --compress zstdSample output for VMID 155:
INFO: starting new backup job: vzdump 155 --storage hdd-backup --mode stop --compress zstd
INFO: Starting Backup of VM 155 (lxc)
INFO: Backup started at 2026-05-30 13:50:04
INFO: status = stopped
INFO: backup mode: stop
INFO: CT Name: forge
INFO: creating vzdump archive '/mnt/hdd/proxmox-backups/dump/vzdump-lxc-155-2026_05_30-13_50_04.tar.zst'
INFO: Total bytes written: 672266240 (642MiB, 132MiB/s)
INFO: archive file size: 196MB
INFO: Finished Backup of VM 155 (00:00:48)
INFO: Backup job finished successfullyThese one-time backups are not part of the automated schedule.
Part 3 — Offsite Sync to Google Drive
Why bother with Google Drive?
Local HDD backups are great, but they won't survive a house fire or a drive failure that takes the HDD with it. Syncing the latest backup per container to Google Drive gives you an offsite copy without paying for S3 or Backblaze.
We use rclone for this — it's a Swiss Army knife for cloud storage sync and has excellent Google Drive support.
Step 3.1 — Install rclone
apt install rclone -yStep 3.2 — Configure the Google Drive remote
Run the interactive config and follow the prompts:
rclone configKey choices:
- Select
nfor new remote - Name it
gdrive - Storage type:
18(Google Drive) - Leave
client_idandclient_secretblank - Scope:
1(full access) - Leave all other fields blank
- Advanced config:
n
For the OAuth step — if you're on a headless server (which Proxmox is), you have two options:
Option A (easier): Say Y to auto config — rclone will print a local URL like http://127.0.0.1:53682/auth?.... From your local machine, open an SSH tunnel:
# Run this on your LOCAL machine (not the Proxmox host)
ssh -L 53682:localhost:53682 root@192.168.0.150Then open the URL in your browser, authorize, and the terminal on the Proxmox host will receive the code automatically.
Option B: Say N to auto config — rclone will give you a URL to open in any browser, and you paste the code back manually.
After authorizing, confirm with y and quit config with q.
Verify and create the target folder:
rclone lsd gdrive:
rclone mkdir gdrive:proxmox-backupsStep 3.3 — Create the GDrive sync script
This script finds the most recent backup file for each container on the HDD, uploads it to Google Drive, and deletes any older backups for that container from Drive. The result: exactly one backup per container in GDrive at all times.
cat > /usr/local/bin/gdrive-sync.sh << 'EOF'
#!/bin/bash
BACKUP_DIR="/mnt/hdd/proxmox-backups/dump"
GDRIVE_DIR="gdrive:proxmox-backups"
LOG="/var/log/gdrive-sync.log"
DATE=$(date '+%Y-%m-%d %H:%M:%S')
VMIDS="151 152 153 154"
echo "[$DATE] Starting GDrive sync" >> $LOG
for VMID in $VMIDS; do
LATEST=$(ls -t "$BACKUP_DIR"/vzdump-lxc-${VMID}-*.tar.zst 2>/dev/null | head -1)
if [ -z "$LATEST" ]; then
echo "[$DATE] No backup found for VMID $VMID, skipping" >> $LOG
continue
fi
FILENAME=$(basename "$LATEST")
echo "[$DATE] Syncing $FILENAME to GDrive" >> $LOG
rclone copy "$LATEST" "$GDRIVE_DIR" \
--transfers 1 \
--drive-chunk-size 128M \
--log-file "$LOG" \
--log-level INFO
# Delete older backups for this VMID from GDrive (keep only latest)
rclone lsf "$GDRIVE_DIR" --files-only | \
grep "vzdump-lxc-${VMID}-" | \
grep -v "$FILENAME" | \
while read OLD; do
echo "[$DATE] Removing old GDrive backup: $OLD" >> $LOG
rclone delete "$GDRIVE_DIR/$OLD" >> $LOG 2>&1
done
done
echo "[$DATE] GDrive sync complete" >> $LOG
EOF
chmod +x /usr/local/bin/gdrive-sync.shPart 4 — Scheduling with Cron
Now we tie it all together. The schedule is staggered intentionally: LXC backups run first, then the GDrive sync picks up the freshly written files two hours later.
| Task | Schedule | Time |
|---|---|---|
| LXC backup to HDD | Wednesday + Sunday | 2:00 AM |
| GDrive sync | Wednesday + Sunday | 4:00 AM |
| Git config backup | Monday + Thursday + Saturday | 3:00 AM |
crontab -eAdd these lines:
# LXC backup to HDD — Wed and Sun at 2AM
0 2 * * 0,3 /usr/local/bin/lxc-backup.sh
# GDrive sync — Wed and Sun at 4AM (2 hours after backup starts)
0 4 * * 0,3 /usr/local/bin/gdrive-sync.sh
# Git config backup — Mon, Thu, Sat at 3AM
0 3 * * 1,4,6 /usr/local/bin/git-config-backup.shConfirm the crontab was saved:
crontab -lPart 5 — Version the Scripts Themselves
This is a small but important step. We copy the three backup scripts into the git repo so they're versioned and recoverable. If you ever rebuild the server, you can pull the scripts directly from GitHub instead of recreating them from memory.
mkdir -p /opt/homelab-config-backup/scripts
cp /usr/local/bin/git-config-backup.sh /opt/homelab-config-backup/scripts/
cp /usr/local/bin/lxc-backup.sh /opt/homelab-config-backup/scripts/
cp /usr/local/bin/gdrive-sync.sh /opt/homelab-config-backup/scripts/cd /opt/homelab-config-backup
git add scripts/
git commit -m "add backup scripts"
git push origin mainFrom here on, every time git-config-backup.sh runs, it does git add -A which will automatically pick up any modifications to the scripts directory as well.
Part 6 — Test Everything Manually
Before trusting cron to do this overnight, run each script once and check the logs.
# Test git config backup
/usr/local/bin/git-config-backup.sh
cat /var/log/git-config-backup.logExpected log output:
[2026-05-30 15:49:50] Starting config backup
[2026-05-30 15:49:50] Pushed to GitHub successfully# Test LXC backup
/usr/local/bin/lxc-backup.sh
cat /var/log/lxc-backup.logExpected:
[2026-05-30 15:50:34] Starting LXC backup
[2026-05-30 15:50:34] Backing up VMID 151
[2026-05-30 15:50:34] VMID 151 backup complete
...
[2026-05-30 15:50:34] LXC backup complete# Test GDrive sync (run after the LXC backup completes)
/usr/local/bin/gdrive-sync.sh
cat /var/log/gdrive-sync.logThe GDrive sync will take a while depending on container sizes — rclone logs progress every minute. VMID 151 in the test run was ~5.4 GiB and took about 3.5 minutes. When it's done you should see something like:
[2026-05-30 16:17:25] GDrive sync completeVerify files landed on GDrive:
rclone lsf gdrive:proxmox-backupsvzdump-lxc-151-2026_05_30-15_50_34.tar.zst
vzdump-lxc-152-2026_05_30-15_52_34.tar.zst
vzdump-lxc-153-2026_05_30-15_52_58.tar.zst
vzdump-lxc-154-2026_05_30-15_54_15.tar.zstVerify files on HDD:
ls -lh /mnt/hdd/proxmox-backups/dump/And open your GitHub repo in a browser to confirm the config files and scripts are committed.
Log File Reference
| Log | Path |
|---|---|
| LXC backup | /var/log/lxc-backup.log |
| GDrive sync | /var/log/gdrive-sync.log |
| Git config backup | /var/log/git-config-backup.log |
To tail any log in real time:
tail -f /var/log/lxc-backup.logRestore Playbook
Restore a single LXC from HDD
# List what's available
ls /mnt/hdd/proxmox-backups/dump/
# Restore (swap out the VMID and filename)
pct restore 153 /mnt/hdd/proxmox-backups/dump/vzdump-lxc-153-YYYY_MM_DD-HH_MM_SS.tar.zst \
--storage local-lvm \
--startRestore a single LXC from Google Drive
# Pull down from GDrive first
rclone copy gdrive:proxmox-backups/vzdump-lxc-153-*.tar.zst /mnt/hdd/proxmox-backups/dump/
# Then restore as above
pct restore 153 /mnt/hdd/proxmox-backups/dump/vzdump-lxc-153-*.tar.zst \
--storage local-lvm \
--startFull host recovery (fresh Proxmox install)
If you're starting from scratch after a reinstall:
- Re-add the HDD storage so Proxmox can see existing backups:
pvesm add dir hdd-backup --path /mnt/hdd/proxmox-backups --content backup- Restore network config from GitHub:
git clone git@github.com:YOUR_USERNAME/homelab-config-backup.git /tmp/config-restore
cp /tmp/config-restore/interfaces /etc/network/interfaces
systemctl restart networking- Restore each container:
pct restore 151 /mnt/hdd/proxmox-backups/dump/vzdump-lxc-151-*.tar.zst --storage local-lvm
pct restore 152 /mnt/hdd/proxmox-backups/dump/vzdump-lxc-152-*.tar.zst --storage local-lvm
pct restore 153 /mnt/hdd/proxmox-backups/dump/vzdump-lxc-153-*.tar.zst --storage local-lvm
pct restore 154 /mnt/hdd/proxmox-backups/dump/vzdump-lxc-154-*.tar.zst --storage local-lvm- Start all containers:
for VMID in 151 152 153 154; do pct start $VMID; done- Re-authorize rclone for Google Drive (OAuth tokens don't survive a reinstall):
rclone config
# Follow Part 3, Step 3.2 againWhat You End Up With
After following this guide, your backup posture looks like this:
- GitHub — full Proxmox config history, committed 3× per week, recoverable in seconds
- Local HDD — 2 rolling LXC snapshots per container, backed up 2× per week
- Google Drive — 1 offsite copy per container, synced every backup run
Three independent failure modes means you'd have to lose all three simultaneously to truly be stuck. For a home server, that's a pretty good place to be.