🔗 Proxmox Rclone Backup Manual – Fully Automated, Encrypted & Reliable

Fully automated, client-side encrypted Proxmox VE backups to iDrive E2 with rclone: monthly rotation, retention, Dual-WAN upload and restore guide.

Category
🔐 Backup
Requirements
Described in the guide
Code blocks
10

This comprehensive guide provides a complete, secure, and fully automated backup solution for Proxmox VE using rclone with client-side encrypted iDrive E2 cloud storage. The system is designed for maximum reliability, performance, and security.

Key Features:

  • Monthly backup cycle with automatic retention (max. 5 months)
  • Retention runs only after a successful upload and content verification
  • Full AES-256-CTR encryption with HMAC-SHA256 integrity
  • High-performance upload with 8 parallel transfers and 64M chunks
  • Background execution via screen with live progress monitoring
  • Comprehensive logging and detailed email reports
  • Lockfile protection against concurrent runs
  • Optional dual-WAN routing for dedicated upload bandwidth

Script 1: rclone_backup.sh – Core Backup Engine (FINAL VERSION)

Purpose: Fully automated monthly backup with encryption, retention, and monitoring.

Key Improvements Over Basic Scripts:

  • Safe Retention: Validates the source, uploads and verifies files before deleting old months
  • Live Status: Logs upload progress and each old month removed
  • Robust Error Handling: Stops on upload, verification or retention errors
  • Listing Validation: Remote listing errors abort retention
  • Performance Optimized: 8 transfers, 16 checkers, 64M chunks, 256M buffer
  • Long-Run Protection: Warning email if upload exceeds 24 hours
  • Final Verification: Downloads and compares selected files through the encrypted remote
Bash
#!/usr/bin/env bash
set -euo pipefail
umask 077

# Configuration: run this complete script inside screen if desired.
logfile="/var/log/rclone_backup.log"
lockfile="/var/run/rclone_backup.lock"
email="mail@server.de"
backup_source="/mnt/USBBackup/dump/"
backup_target="idrive-enc:"
retention_limit=5
max_expected_hours=24
current_date=$(date +%Y-%m)
month_tag=$(date +%Y_%m)

log() { printf '[%s] %s\n' "$(date '+%F %T')" "$1" | tee -a "$logfile"; }
for cmd in rclone flock find sort; do
  command -v "$cmd" >/dev/null || { echo "Missing dependency: $cmd" >&2; exit 1; }
done
[[ -n "$backup_target" ]] || exit 1
exec 9>"$lockfile"
flock -n 9 || { log "Another backup is already running."; exit 1; }
# Never unlink the lock file: all processes must lock the same inode.
work_dir=$(mktemp -d)
upload_pid=''
cleanup() {
  local status=$?
  trap - EXIT
  if [[ -n "$upload_pid" ]]; then
    kill "$upload_pid" 2>/dev/null || true
    wait "$upload_pid" 2>/dev/null || true
  fi
  [[ ! -f "$work_dir/upload.log" ]] || cat "$work_dir/upload.log" >> "$logfile" || true
  rm -rf -- "$work_dir"
  exit "$status"
}
trap cleanup EXIT
trap 'exit 130' INT
trap 'exit 143' TERM

# Validate the source before creating or deleting anything remotely.
cd "$backup_source" || { log "Source directory inaccessible."; exit 1; }
find . -type f -name "*$month_tag*.zst" -printf '%P\n' > "$work_dir/files"
if [[ ! -s "$work_dir/files" ]]; then
  log "No backups for $month_tag; remote backups left unchanged."
  exit 0
fi
target_path="$backup_target$current_date"
log "Uploading backups to $target_path"
rclone copy . "$target_path" --files-from-raw "$work_dir/files" \
  --log-file "$work_dir/upload.log" --log-level INFO \
  --transfers 8 --checkers 16 --s3-chunk-size 64M --buffer-size 256M \
  --retries 10 --low-level-retries 20 --timeout 5m --stats 10s &
upload_pid=$!
started=$SECONDS
warned=0
while kill -0 "$upload_pid" 2>/dev/null; do
  if (( SECONDS - started >= max_expected_hours * 3600 && warned == 0 )); then
    warned=1
    log "WARNING: Upload running longer than $max_expected_hours hours."
    printf 'To: %s\nSubject: Backup taking too long\n\nCheck %s\n' "$email" "$logfile" \
      | /usr/sbin/sendmail -t -i || log "Warning email failed."
  fi
  sleep 5
done
upload_status=0
wait "$upload_pid" || upload_status=$?
upload_pid=''
if (( upload_status != 0 )); then
  log "Upload failed (exit $upload_status); retention skipped."
  exit "$upload_status"
fi

# Verify the selected files through the decrypted remote before retention.
# --download compares content even when encrypted remote hashes are unavailable.
if ! rclone check . "$target_path" --files-from-raw "$work_dir/files" --one-way --download; then
  log "Verification failed; retention skipped."
  exit 1
fi

# A failed listing must never be treated as an empty/successful result.
rclone lsf --dirs-only "$backup_target" > "$work_dir/directories"
sed -nE 's#^([0-9]{4}-(0[1-9]|1[0-2]))/$#\1#p' "$work_dir/directories" | sort -r > "$work_dir/months"
mapfile -t months < "$work_dir/months"
for ((i=retention_limit; i<${#months[@]}; i++)); do
  month=${months[$i]}
  [[ "$month" < "$current_date" ]] || continue
  log "Removing old backup month $month after successful verification."
  rclone delete "$backup_target$month/" --rmdirs
done
log "Backup upload and verification completed."
printf 'To: %s\nSubject: Backup completed\n\nVerified backup: %s\n' "$email" "$target_path" \
  | /usr/sbin/sendmail -t -i

Script 2: rclone_backup_dualwan.sh – Dedicated Upload Line (Optional)

Use Case: Route backup traffic through a secondary WAN interface (e.g., 4G/5G) to avoid congesting primary internet.

Requirements:

  • Secondary gateway reachable (e.g., 192.168.123.2)
  • Interface vmbr0 or similar
  • Routing table 200 secondgw in /etc/iproute2/rt_tables
Bash
echo "200 secondgw" >> /etc/iproute2/rt_tables
Bash
#!/bin/bash
# =============================================================================
# Dual-WAN Backup Router – Routes rclone traffic via secondary gateway
# =============================================================================
set -euo pipefail

# Root check
if [[ $EUID -ne 0 ]]; then
  echo "This script must be run as root."
  exit 1
fi

# === CONFIG ===
SECOND_GW="192.168.123.2"           # ← Secondary gateway IP
TABLE_NAME="secondgw"
TABLE_ID="200"
RCLONE_BACKUP_SCRIPT="/usr/local/bin/rclone_backup.sh"
DEVICE="vmbr0"                      # ← Your network interface
logfile="/var/log/rclone_backup_dualwan.log"

log() {
  echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$logfile"
}

log "===== Starting Dual-WAN Backup via $SECOND_GW ====="

# Ensure routing table exists
if ! grep -q "^$TABLE_ID[[:space:]]\+$TABLE_NAME" /etc/iproute2/rt_tables; then
  echo "$TABLE_ID $TABLE_NAME" >> /etc/iproute2/rt_tables
  log "Routing table '$TABLE_NAME' (ID $TABLE_ID) created."
fi

# Setup routing
ip route flush table "$TABLE_NAME" || true
ip route add default via "$SECOND_GW" dev "$DEVICE" table "$TABLE_NAME"
ip rule add fwmark 0x1 table "$TABLE_NAME"
iptables -t mangle -A OUTPUT -p tcp --dport 443 -m owner --uid-owner root -j MARK --set-mark 1

log "Starting backup via secondary gateway..."
if bash "$RCLONE_BACKUP_SCRIPT"; then
  log "Backup completed successfully."
else
  log "Backup failed!"
fi

# Cleanup
log "Removing temporary routing rules..."
iptables -t mangle -D OUTPUT -p tcp --dport 443 -m owner --uid-owner root -j MARK --set-mark 1 || true
ip rule del fwmark 0x1 table "$TABLE_NAME" || true
ip route flush table "$TABLE_NAME" || true
log "Dual-WAN backup completed."

Rclone Configuration – Encrypted Remote

File: ~/.config/rclone/rclone.conf

Config
[idrive-e2]
type = s3
provider = IDrive
access_key_id = YOUR_ACCESS_KEY_ID
secret_access_key = YOUR_SECRET_ACCESS_KEY
acl = private
endpoint = node.nl32.idrivee2-3.com
bucket_acl = private

[idrive-enc]
type = crypt
remote = idrive-e2:proxmox-backups
filename_encryption = off
directory_name_encryption = false
password = YOUR_CRYPT_PASSWORD

Security Notes:

  • Encryption: AES-256-CTR with HMAC-SHA256
  • Password: 64 characters → >10^50 years to crack
  • Filename Encryption: Off → readable logs, encrypted content
  • Salt: Not needed (scrypt built-in)

Restore from iDrive E2

Step-by-Step Restore:

  1. List files:
    Bash
    rclone ls idrive-enc:2025-06
  2. Download backup:
    Bash
    rclone copy idrive-enc:2025-06/vzdump-qemu-100-2025_06_01.vma.zst /var/lib/vz/dump/
  3. Restore VM:
    Bash
    qmrestore /var/lib/vz/dump/vzdump-qemu-100-2025_06_01.vma.zst 100

Integrity Check (Recommended):

Bash
zstd -t /var/lib/vz/dump/vzdump-qemu-100-2025_06_01.vma.zst

Cronjob – Automated Monthly Execution

Recommended: Run on the 1st of each month at 02:00 AM

Cron
0 2 1 * * /usr/local/bin/rclone_backup.sh >> /var/log/rclone_backup_cron.log 2>&1

Alternative (with screen):

Cron
0 3 1 * * /usr/bin/screen -dmS monthly-backup /usr/local/bin/rclone_backup.sh

Performance & Security Summary

FeatureImplementation
EncryptionAES-256-CTR + HMAC-SHA256
Password Strength64 chars → uncrackable
RetentionMax 5 months, safe deletion
Speed8 transfers, 64M chunks, 256M buffer
Reliability10 retries, 5m timeout, lockfile
MonitoringOptional screen + email + logs

Troubleshooting

  • Check logs: tail -f /var/log/rclone_backup.log
  • Live progress: tail -f /var/log/rclone_backup.log; when started with the example screen cronjob, use screen -r monthly-backup
  • Test encryption: rclone cat idrive-enc:2025-11/test.txt
  • List buckets: rclone lsf idrive-enc:

Final Notes

  • Automated and encrypted; test backup and restore with your own configuration
  • Works with Proxmox Backup Server or manual vzdump
  • Zero downtime – runs in background
  • Full audit trail with logs and emails
  • Optional dual-WAN for dedicated bandwidth

Your Proxmox data is now protected with verified uploads and post-upload retention.

← Back to all scripts