BorgBackup Advanced Strategies
BorgBackup is a deduplicating, compressing, encrypting backup tool widely used in enterprise Linux environments. This guide covers advanced BorgBackup strategies including append-only mode for ransomware protection, remote repositories over SSH, compression tuning, parallel operations, monitoring, and disaster recovery procedures.
Prerequisites
- Ubuntu/Debian or CentOS/Rocky Linux
- BorgBackup 1.2+
- SSH access to a remote backup server (for remote repos)
- At least 1 GB RAM for compression operations on large datasets
Installation and Repository Setup
# Ubuntu/Debian
sudo apt-get install -y borgbackup
# CentOS/Rocky
sudo dnf install -y borgbackup
# Or install latest binary
pip3 install borgbackup
# Verify installation
borg --version
# Create passphrase file (protect with strict permissions)
echo "your-strong-borg-passphrase" > /root/.borg-passphrase
chmod 600 /root/.borg-passphrase
# Export passphrase for borg commands
export BORG_PASSPHRASE="$(cat /root/.borg-passphrase)"
# Initialize local repository with encryption
borg init --encryption=repokey-blake2 /backup/borg-repo
# Export and SAVE the repository key (critical for recovery!)
borg key export /backup/borg-repo /root/.borg-repokey-backup
# Store this key offline - you cannot recover data without it
Append-Only Mode for Ransomware Protection
Append-only mode prevents deletion or modification of existing archives — a compromised client cannot destroy backups:
# Initialize a repository in append-only mode
borg init --encryption=repokey-blake2 --append-only /backup/append-only-repo
# Create backups normally - archives can only be added
borg create /backup/append-only-repo::{hostname}-{now:%Y-%m-%d} /etc /home
# Pruning must be done from a trusted admin machine
# The admin uses a separate key with full access
# On the SERVER with full access:
borg compact /backup/append-only-repo
# For remote append-only repos, use restricted SSH key
# The backup client's SSH key is restricted with borg serve --append-only
Restricted SSH Key for Remote Append-Only
On the backup SERVER, add to ~/.ssh/authorized_keys:
# Prepend to the SSH key line to restrict it to append-only borg
command="borg serve --append-only --restrict-to-path /srv/borg/client01",restrict ssh-ed25519 AAAA... backupclient@client01
Full access key for admin operations (pruning, compacting):
command="borg serve --restrict-to-path /srv/borg/client01",restrict ssh-ed25519 AAAA... admin@management
Remote Repositories over SSH
# SSH repository format: user@host:path
# Initialize remote repository
borg init \
--encryption=repokey-blake2 \
[email protected]:/srv/borg/server01
# Specify SSH key explicitly
BORG_RSH="ssh -i /root/.ssh/borg_backup_key" \
borg init \
--encryption=repokey-blake2 \
[email protected]:/srv/borg/server01
# Set persistent SSH options via env
export BORG_RSH="ssh -i /root/.ssh/borg_key -o StrictHostKeyChecking=no -o ConnectTimeout=10"
# Create remote backup
borg create \
[email protected]:/srv/borg/server01::{hostname}-{now:%Y-%m-%dT%H:%M:%S} \
/etc /home /var/www \
--exclude /home/*/.cache \
--stats \
--progress
Complete Backup Script for Remote Repository
cat > /usr/local/bin/borg-backup.sh << 'SCRIPT'
#!/bin/bash
set -euo pipefail
# Configuration
export BORG_REPO="[email protected]:/srv/borg/$(hostname)"
export BORG_PASSPHRASE="$(cat /root/.borg-passphrase)"
export BORG_RSH="ssh -i /root/.ssh/borg_key -o ServerAliveInterval=60"
BACKUP_DIRS="/etc /home /var/www /opt"
ARCHIVE_NAME="{hostname}-{now:%Y-%m-%dT%H:%M:%S}"
# Trap errors to send alert
trap 'echo "Borg backup FAILED on $(hostname) at $(date)" | \
mail -s "BACKUP FAILED: $(hostname)" [email protected]' ERR
echo "=== Borg backup started: $(date) ==="
borg create \
--verbose \
--filter AME \
--list \
--stats \
--show-rc \
--compression lz4 \
--exclude-caches \
--exclude '/home/*/.cache' \
--exclude '/var/cache' \
--exclude '/tmp' \
--exclude '*.pyc' \
"$BORG_REPO::$ARCHIVE_NAME" \
$BACKUP_DIRS
echo "=== Pruning old archives ==="
borg prune \
--list \
--glob-archives "{hostname}-*" \
--show-rc \
--keep-daily 7 \
--keep-weekly 4 \
--keep-monthly 6 \
"$BORG_REPO"
echo "=== Compacting repository ==="
borg compact "$BORG_REPO"
echo "=== Backup complete: $(date) ==="
SCRIPT
chmod +x /usr/local/bin/borg-backup.sh
Compression Tuning
Borg supports several compression algorithms with different speed/ratio tradeoffs:
# lz4: Fast compression, lower ratio (best for daily backups)
borg create --compression lz4 /backup/repo::backup-lz4 /data
# zstd: Good balance of speed and ratio (recommended)
borg create --compression zstd /backup/repo::backup-zstd /data
# zstd with specific level (1-22, higher = smaller but slower)
borg create --compression zstd,3 /backup/repo::backup-zstd3 /data # Fast
borg create --compression zstd,15 /backup/repo::backup-zstd15 /data # Slow, small
# lzma: Maximum compression, slowest (use for archival/cold storage)
borg create --compression lzma,6 /backup/repo::archive /data
# auto: Let Borg decide based on file type
borg create --compression auto,lz4 /backup/repo::backup-auto /data
# Benchmark compression on your actual data
borg benchmark crud /tmp/borg-bench /data
Pruning and Retention Policies
# Prune with a detailed retention policy
borg prune \
--list \
--show-rc \
--keep-within 2d \ # Keep all archives from last 2 days
--keep-hourly 24 \ # Keep 24 hourly archives
--keep-daily 7 \ # Keep 7 daily archives
--keep-weekly 4 \ # Keep 4 weekly archives
--keep-monthly 12 \ # Keep 12 monthly archives
--keep-yearly 3 \ # Keep 3 yearly archives
--glob-archives "{hostname}-*" \ # Only prune matching archives
/backup/borg-repo
# Dry run to preview what would be deleted
borg prune --dry-run --list --keep-daily 7 /backup/borg-repo
# Compact after prune (frees actual disk space)
borg compact /backup/borg-repo
Monitoring and Alerting
Systemd Integration
# /etc/systemd/system/borg-backup.service
[Unit]
Description=BorgBackup
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/borg-backup.sh
StandardOutput=journal
StandardError=journal
Environment="BORG_PASSPHRASE="
EnvironmentFile=/etc/borg/environment
[Install]
WantedBy=multi-user.target
# /etc/systemd/system/borg-backup.timer
[Unit]
Description=BorgBackup daily timer
[Timer]
OnCalendar=02:00
RandomizedDelaySec=30m
Persistent=true
[Install]
WantedBy=timers.target
# Store credentials securely
sudo mkdir -p /etc/borg
sudo tee /etc/borg/environment << 'EOF'
BORG_PASSPHRASE=your-passphrase
BORG_RSH=ssh -i /root/.ssh/borg_key
EOF
sudo chmod 600 /etc/borg/environment
sudo systemctl daemon-reload
sudo systemctl enable --now borg-backup.timer
Healthchecks Integration
# Send ping to healthchecks.io on success/failure
HEALTHCHECK_URL="https://hc-ping.com/your-uuid"
# At start of backup script:
curl -m 10 --retry 3 "$HEALTHCHECK_URL/start"
# At end of backup script (success):
curl -m 10 --retry 3 "$HEALTHCHECK_URL"
# On failure (in trap):
curl -m 10 --retry 3 "$HEALTHCHECK_URL/fail" -d "Backup failed: $?"
Parallel Operations
# Run backups for multiple clients in parallel from an orchestration server
backup_client() {
local host=$1
local repo="/srv/borg/$host"
echo "Starting backup for $host"
ssh -i /root/.ssh/borg_key "backupuser@$host" \
"BORG_PASSPHRASE=secret borg create $repo::{hostname}-{now} /etc /home" \
&& echo "Backup complete for $host" \
|| echo "BACKUP FAILED for $host"
}
export -f backup_client
parallel -j 4 backup_client ::: server1 server2 server3 server4
# Or use xargs for parallel execution
echo "server1 server2 server3 server4" | tr ' ' '\n' | \
xargs -P 4 -I {} bash -c 'backup_client {}'
Disaster Recovery
# List all archives in a repository
borg list /backup/borg-repo
# List contents of a specific archive
borg list /backup/borg-repo::server01-2024-01-15T02:00:00
# Extract specific files from an archive
mkdir -p /restore
cd /restore
borg extract /backup/borg-repo::server01-2024-01-15T02:00:00 \
home/user/important-files
# Extract entire archive
borg extract /backup/borg-repo::server01-2024-01-15T02:00:00
# Extract with dry run (see what would be extracted)
borg extract --dry-run --list /backup/borg-repo::server01-2024-01-15T02:00:00
# Mount an archive as a filesystem (requires FUSE)
sudo apt-get install -y borgbackup-fuse
mkdir -p /mnt/borg-restore
borg mount /backup/borg-repo::server01-2024-01-15T02:00:00 /mnt/borg-restore
ls /mnt/borg-restore
# Copy specific files
cp -r /mnt/borg-restore/var/www/myapp /restore/
# Unmount
borg umount /mnt/borg-restore
Troubleshooting
Repository lock left behind:
# Only break lock if no backup is running
borg break-lock /backup/borg-repo
# Check for running borg processes first
ps aux | grep borg
SSH connection timeout during backup:
# Add keepalive to BORG_RSH
export BORG_RSH="ssh -i /root/.ssh/borg_key -o ServerAliveInterval=60 -o ServerAliveCountMax=10"
"Repository is corrupted" errors:
# Check repository integrity
borg check --repository-only /backup/borg-repo
# Check archives too (slower)
borg check /backup/borg-repo
# Repair if possible
borg check --repair /backup/borg-repo
High memory usage during backup:
# Borg uses chunker cache - limit with env var
export BORG_FILES_CACHE_TTL=20
# Or reduce chunk cache size
export BORG_CACHE_DIR=/tmp/borg-cache
Conclusion
BorgBackup's append-only mode combined with remote repositories provides enterprise-grade backup security against both accidental deletion and ransomware. Its deduplication ensures even frequent backups remain storage-efficient, while flexible compression tuning lets you balance speed against storage costs based on your data types. With systemd timer integration and monitoring pings, you can operate a reliable, automated backup infrastructure with minimal ongoing maintenance.


