VPS Backup Automation with BorgBackup: Deduplication, Pruning & systemd Timers
A complete guide to automating secure, deduplicated Linux VPS backups using BorgBackup, SSH key authentication, retention pruning, and systemd timers.
Automating backups on an unmanaged Linux KVM VPS requires an approach that balances storage efficiency, network bandwidth, and cryptographic security. BorgBackup provides authenticated, chunk-level deduplication and client-side encryption over SSH, allowing system administrators to create rapid daily snapshots that consume minimal remote disk space while retaining historical versions via automated pruning policies.
Why Traditional Backups Fail on Cloud Servers
Traditional file-level rsync mirrors create exact copies but consume massive remote storage when retaining historical point-in-time revisions. Tar archives, while portable, duplicate unchanged data repeatedly, wasting bandwidth and disk blocks. BorgBackup solves this by breaking files into variable-length chunks, calculating cryptographic hashes, and saving only unique chunks into an encrypted repository.
Step 1: Install and Initialize the Borg Repository
Install BorgBackup on your Linux VPS via the native package manager:
# On Debian/Ubuntu
apt update && apt install -y borgbackup
# On RHEL/AlmaLinux
dnf install -y epel-release && dnf install -y borgbackupGenerate an SSH key pair for the backup user and initialize the remote repository using authenticated client-side encryption:
# Generate dedicated SSH key
ssh-keygen -t ed25519 -N "" -f /root/.ssh/id_borg_backup
# Initialize remote repository (replace with your remote storage server)
export BORG_REPO="ssh://backupuser@storage.example.com/backups/vps-repo"
export BORG_PASSPHRASE="YourSecurePassphraseHere"
borg init --encryption=repokey-zstd $BORG_REPOStep 2: Create the Backup and Prune Script
Create an automated backup script at /usr/local/bin/vps-backup.sh. The script defines which system paths to back up, enforces compression, prunes historical archives, and compacts the repository:
#!/usr/bin/env bash
set -e
export BORG_REPO="ssh://backupuser@storage.example.com/backups/vps-repo"
export BORG_PASSPHRASE="YourSecurePassphraseHere"
export BORG_RSH="ssh -i /root/.ssh/id_borg_backup"
ARCHIVE_NAME="{hostname}-$(date +%Y-%m-%d_%H%M%S)"
# 1. Create the backup archive with zstd compression
echo "Creating backup archive: $ARCHIVE_NAME"
borg create --stats --compression zstd,3 \
--exclude '/var/cache' \
--exclude '/var/tmp' \
--exclude '/tmp' \
$BORG_REPO::$ARCHIVE_NAME /etc /var/www /home
# 2. Prune old archives (Keep 7 daily, 4 weekly, 6 monthly)
echo "Pruning historical archives"
borg prune --list --keep-daily 7 --keep-weekly 4 --keep-monthly 6 $BORG_REPO
# 3. Compact repository to reclaim deleted blocks
echo "Compacting repository"
borg compact $BORG_REPO
echo "Backup workflow completed successfully."Set strict execution permissions to protect your repository passphrase:
chmod 700 /usr/local/bin/vps-backup.shStep 3: Automate with systemd Service and Timer
While traditional cron jobs can execute scripts, modern Linux administrators prefer systemd timers for server automation. Systemd timers provide native execution logging in journalctl, persistent execution (running missed jobs if the server was offline), and clean dependency management.
Create the Service Unit
Create /etc/systemd/system/borg-backup.service:
[Unit]
Description=Daily BorgBackup Automation Service
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/vps-backup.sh
StandardOutput=journal
StandardError=journalCreate the Timer Unit
Create /etc/systemd/system/borg-backup.timer:
[Unit]
Description=Run BorgBackup Daily at 02:30 AM
Requires=borg-backup.service
[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true
[Install]
WantedBy=timers.targetEnable and Activate the Timer
systemctl daemon-reload
systemctl enable --now borg-backup.timer
systemctl list-timers --allHardening Repositories with Append-Only Mode
To defend against ransomware attacks where an adversary compromises the VPS and attempts to delete off-site backups, configure append-only mode on the destination storage server. In the backup server's ~/.ssh/authorized_keys, restrict the client key:
command="borg serve --append-only --restrict-to-path /backups/vps-repo",no-pty,no-agent-forwarding ssh-ed25519 AAAAC3...In append-only mode, the VPS can write new backup archives but cannot delete, prune, or overwrite existing historical snapshots. Pruning must then be triggered periodically from a separate, trusted administrative workstation.
Step 4: Testing Disaster Recovery Restores
A backup that has never been restored is merely a hypothesis. Regularly verify repository integrity and test recovery procedures:
# Check repository consistency
borg check $BORG_REPO
# List existing point-in-time archives
borg list $BORG_REPO
# Extract a specific file from an archive for verification
mkdir -p /tmp/restore-test && cd /tmp/restore-test
borg extract $BORG_REPO::<archive_name> etc/hostsMonitoring and Alerting on Backup Failures
Automated backup routines should never fail silently. When storage targets fill up, SSH keys expire, or network partitions occur, system administrators need immediate alerting. Integrate proactive webhook notifications or monitoring checks directly into your systemd execution workflow:
- Webhook Ping Integration: Append a simple curl ping to a monitoring heartbeat service (such as Healthchecks.io or an internal monitoring endpoint) at the conclusion of
vps-backup.sh. If the script errors out before reaching the ping, the monitoring system triggers an alert. - Systemd Failure Triggers: Utilize systemd's native
OnFailure=status-email@%n.servicedirective in the unit configuration to dispatch diagnostic alerts whenever the backup service exits with a non-zero status code. - Verify Data Integrity: Run periodic deep consistency checks using
borg check --verify-data $BORG_REPOon a monthly schedule to detect subtle storage hardware bit rot before archives are needed in an emergency.
Infrastructure Reliability on VPSWala
Automated backup strategies require dependable virtual machines that support low-overhead kernel operations. VPSWala delivers unmanaged KVM VPS instances with full root access and high-speed RAID NVMe storage across Mumbai, Noida, and Jaipur nodes. With plans starting from Rs 149 per month for standard cloud instances and dedicated AMD Ryzen 9 9950X VPS tiers for resource-intensive workloads, developers retain total control over their data retention and backup architecture.
Review scalable options on VPSWala Cloud VPS or explore high-frequency computing on VPSWala AMD 9950X VPS.
Sources
Not sure which size?
Send the stack, get a size.
Tell us the operating system, application stack, current traffic, database size and where it hurts today. You get a sizing recommendation, the matching plan and a price.
Related
Deploying Next.js SSR on a Linux VPS: Standalone Build, PM2 & Nginx Proxy
Learn how to deploy a server-rendered Next.js application on a Linux KVM VPS using standalone build artifacts, PM2 cluster management, and Nginx.
VPS Firewall Setup with UFW and iptables: Port Hardening & Lockout Prevention
A hands-on sysadmin guide to securing a Linux cloud VPS with UFW and iptables, implementing strict ingress filtering while preventing accidental connection loss.
VPS Hosting for Bhopal: Which VPSWala Node to Pick and How to Test It
A practical routing and workload sizing guide for developers and businesses in Bhopal to evaluate VPSWala cloud nodes and verify network path stability.