Backup with BorgBackup: Complete Deduplication and Encryption Guide

Introduction

BorgBackup (short for Borg) is a modern, sophisticated backup solution that revolutionizes how Linux systems handle data protection through advanced deduplication, compression, and authenticated encryption. Unlike traditional backup tools that store complete file copies for each backup interval, Borg splits data into content-defined chunks and stores each unique chunk only once across all backups. This approach, combined with efficient compression and strong encryption, makes Borg exceptionally space-efficient while maintaining security and performance.

Developed with lessons learned from earlier deduplication backup tools, BorgBackup has become the gold standard for efficient, secure backups in environments ranging from single-server deployments to large-scale infrastructure. Organizations managing terabytes of data with daily backup requirements have achieved storage reduction ratios exceeding 50:1 through Borg's deduplication capabilities, dramatically reducing storage costs while maintaining comprehensive backup histories.

This comprehensive guide explores BorgBackup from fundamental concepts through production deployment, covering installation, repository management, backup automation, deduplication mechanisms, encryption strategies, remote backups, restoration procedures, and real-world implementation scenarios aligned with the 3-2-1 backup rule.

Understanding BorgBackup Architecture

How BorgBackup Works

BorgBackup implements a sophisticated multi-layered architecture:

Content-defined chunking: Instead of backing up entire files, Borg splits data into variable-sized chunks (typically 1-4MB) using a rolling hash algorithm. This ensures that inserting data at the beginning of a file doesn't affect chunk boundaries of the remaining content.

Global deduplication: Borg maintains a global chunk index across all backups. When creating new backups, Borg checks if each chunk already exists in the repository. Only new, unique chunks are stored, regardless of whether identical data appears in different files, directories, or backup archives.

Compression: Each chunk is individually compressed before storage, using algorithms like LZ4 (fast), zstd (balanced), or zlib (high compression). This provides additional space savings beyond deduplication.

Authenticated encryption: All data is encrypted client-side before transmission to the repository. Borg supports multiple encryption modes including authenticated encryption with AES-256-CTR + HMAC-SHA256, ensuring both confidentiality and integrity.

Repository structure: Backups are stored as "archives" within a "repository". Each archive represents a point-in-time backup, but all archives within a repository share the same deduplicated chunk pool.

BorgBackup vs Traditional Backup Solutions

BorgBackup vs rsync/rsnapshot:

  • Rsync/rsnapshot: File-level deduplication via hard links
  • Borg: Block-level deduplication across all data
  • Rsync/rsnapshot: Human-readable directory structures
  • Borg: Encrypted, deduplicated repository format
  • Rsync/rsnapshot: No built-in encryption
  • Borg: Mandatory encryption with authenticated modes

BorgBackup vs traditional tar backups:

  • Tar: Each backup is a separate archive, full file copies
  • Borg: Global deduplication pool, chunk-level storage
  • Tar: Optional compression per archive
  • Borg: Per-chunk compression with multiple algorithms
  • Tar: Unencrypted by default
  • Borg: Encrypted by default

BorgBackup vs cloud backup services:

  • Cloud services: Often proprietary, vendor lock-in
  • Borg: Open source, format documentation available
  • Cloud services: Variable pricing, data egress fees
  • Borg: Use any storage backend (local, SSH, S3-compatible)
  • Cloud services: Encryption keys may be managed by provider
  • Borg: Client-side encryption, you control keys

Key Features and Benefits

Space efficiency: Deduplication ratios of 10:1 to 50:1 or higher depending on data redundancy and backup frequency.

Performance: Incremental backups are extremely fast as only new/changed chunks are processed and stored.

Security: Authenticated encryption protects against both unauthorized access and tampering.

Compression: Multiple compression algorithms with varying speed/ratio trade-offs.

Integrity verification: Built-in consistency checking detects corruption.

Mount capability: Mount any archive as read-only filesystem for browsing and selective restoration.

Pruning: Flexible retention policies automatically remove old backups while preserving deduplicated chunks still referenced by retained archives.

Cross-platform: Works on Linux, macOS, BSD, Windows (via WSL).

Installation

Installing BorgBackup

BorgBackup is available through standard package managers:

Ubuntu/Debian:

# Update package lists
sudo apt update

# Install BorgBackup
sudo apt install borgbackup

# Verify installation
borg --version

CentOS/Rocky Linux/RHEL:

# Enable EPEL repository
sudo dnf install epel-release

# Install BorgBackup
sudo dnf install borgbackup

# Verify installation
borg --version

Install from binary (latest version):

# Download latest binary
cd /tmp
wget https://github.com/borgbackup/borg/releases/download/1.2.7/borg-linux64
chmod +x borg-linux64

# Move to system path
sudo mv borg-linux64 /usr/local/bin/borg

# Verify
borg --version

Expected output:

borg 1.2.x

Installing BorgBackup from Source

For the latest features or custom builds:

# Install build dependencies (Ubuntu/Debian)
sudo apt install python3-dev python3-pip python3-virtualenv \
    libacl1-dev libssl-dev liblz4-dev libzstd-dev pkg-config

# Create virtual environment
python3 -m venv ~/borg-env
source ~/borg-env/bin/activate

# Install via pip
pip install borgbackup

# Verify
borg --version

Repository Initialization

Creating Your First Repository

A Borg repository is the container for all your backup archives:

Local repository:

# Create repository directory
mkdir -p /backup/borg-repo

# Initialize repository with encryption
borg init --encryption=repokey /backup/borg-repo

Remote repository via SSH:

# Initialize on remote server
borg init --encryption=repokey user@backup-server:/backup/borg-repo

Initialize with passphrase:

# Borg will prompt for passphrase
borg init --encryption=repokey /backup/borg-repo
# Enter new passphrase:
# Enter same passphrase again:
# Repository created successfully

Understanding Encryption Modes

BorgBackup offers several encryption modes with different security/convenience trade-offs:

repokey (recommended for most users):

  • Encryption key stored in repository
  • Protected by passphrase
  • Repository can be cloned/moved easily
  • Easier disaster recovery

keyfile:

  • Encryption key stored in ~/.config/borg/keys/
  • More secure (attacker needs both repo and keyfile)
  • Must backup keyfile separately
  • More complex disaster recovery

repokey-blake2 / keyfile-blake2:

  • Same as above but using BLAKE2b instead of SHA-256
  • Faster on modern CPUs

authenticated:

  • No encryption, only authentication
  • Detects tampering but data is readable
  • Use only for non-sensitive data

none:

  • No encryption or authentication
  • Not recommended except for testing

Example with specific mode:

# Recommended: repokey mode
borg init --encryption=repokey /backup/borg-repo

# High security: keyfile mode
borg init --encryption=keyfile /backup/borg-repo

# Performance optimized
borg init --encryption=repokey-blake2 /backup/borg-repo

Key Management

Export encryption key (critical for disaster recovery):

# Export key to file
borg key export /backup/borg-repo /secure/location/borg-key-backup.txt

# Store passphrase securely
# Use password manager, encrypted file, or physical safe

Import key (during recovery):

# Import previously exported key
borg key import /backup/borg-repo /secure/location/borg-key-backup.txt

Change passphrase:

# Change repository passphrase
borg key change-passphrase /backup/borg-repo

Environment Variables for Automation

Set up environment variables for automated backups:

# Add to backup script or .bashrc
export BORG_REPO='/backup/borg-repo'
export BORG_PASSPHRASE='your-secure-passphrase'

# For remote repositories
export BORG_REPO='user@backup-server:/backup/borg-repo'
export BORG_RSH='ssh -i /root/.ssh/borg-backup-key'

Security warning: Storing passphrases in plain text reduces security. Consider:

  • Using SSH agent for remote backups
  • Storing passphrase in encrypted file
  • Using systemd credentials or HashiCorp Vault

Creating Backups

Basic Backup Creation

Create your first backup archive:

# Create backup archive
borg create \
    /backup/borg-repo::backup-2026-01-11 \
    /home \
    /etc \
    /var/www

# Syntax: borg create REPOSITORY::ARCHIVE-NAME SOURCE [SOURCE...]

With timestamp:

# Use date in archive name
borg create \
    /backup/borg-repo::backup-$(date +%Y%m%d-%H%M%S) \
    /home /etc /var/www

Verbose output:

# Show detailed progress
borg create --progress --stats \
    /backup/borg-repo::backup-$(date +%Y%m%d) \
    /home /etc /var/www

Output example:

Creating archive at "/backup/borg-repo::backup-20260111"
------------------------------------------------------------------------------
Archive name: backup-20260111
Archive fingerprint: abc123def456
Time (start): Sat, 2026-01-11 14:30:00
Time (end):   Sat, 2026-01-11 14:35:42
Duration: 5 minutes 42.18 seconds
Number of files: 45231
------------------------------------------------------------------------------
                       Original size      Compressed size    Deduplicated size
This archive:               5.23 GB              3.87 GB              156.32 MB
All archives:              15.69 GB             11.61 GB                3.21 GB
------------------------------------------------------------------------------

Excluding Files and Directories

Optimize backups by excluding unnecessary data:

Using --exclude patterns:

borg create \
    --exclude '*.tmp' \
    --exclude '*.log' \
    --exclude 'cache/' \
    --exclude 'node_modules/' \
    /backup/borg-repo::backup-$(date +%Y%m%d) \
    /home /var/www

Using exclude file:

Create /etc/borg/exclude-patterns.txt:

# Temporary files
*.tmp
*.swp
*.bak
~*

# Caches
.cache/
__pycache__/
*.pyc
node_modules/
vendor/

# Logs
*.log
/var/log/

# System directories
/proc/
/sys/
/dev/
/run/
/tmp/

# Build artifacts
*.o
*.so
.git/

Use in backup command:

borg create \
    --exclude-from /etc/borg/exclude-patterns.txt \
    /backup/borg-repo::backup-$(date +%Y%m%d) \
    /

Compression Options

Borg supports multiple compression algorithms:

No compression (fastest):

borg create --compression none \
    /backup/borg-repo::backup-$(date +%Y%m%d) \
    /home

LZ4 (very fast, moderate compression):

borg create --compression lz4 \
    /backup/borg-repo::backup-$(date +%Y%m%d) \
    /home

Zstd (balanced, recommended):

# Default level (3)
borg create --compression zstd \
    /backup/borg-repo::backup-$(date +%Y%m%d) \
    /home

# Custom level (1-22, higher = better compression, slower)
borg create --compression zstd,10 \
    /backup/borg-repo::backup-$(date +%Y%m%d) \
    /home

Zlib (high compression, slower):

# Level 0-9
borg create --compression zlib,9 \
    /backup/borg-repo::backup-$(date +%Y%m%d) \
    /home

Adaptive compression (auto-detect compressibility):

borg create --compression auto,zstd,10 \
    /backup/borg-repo::backup-$(date +%Y%m%d) \
    /home

Production Backup Script

Comprehensive script for production environments:

#!/bin/bash
# /usr/local/bin/borg-backup.sh

set -e

# Configuration
export BORG_REPO='/backup/borg-repo'
export BORG_PASSPHRASE='your-secure-passphrase'

BACKUP_NAME="backup-$(date +%Y%m%d-%H%M%S)"
LOG_FILE="/var/log/borg-backup.log"
ADMIN_EMAIL="[email protected]"

# Logging function
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"
}

# Error handler
error_exit() {
    log "ERROR: $1"
    echo "Borg backup failed: $1" | mail -s "Backup FAILED - $(hostname)" "$ADMIN_EMAIL"
    exit 1
}

log "Starting Borg backup: $BACKUP_NAME"

# Pre-backup: Database dumps
log "Creating database dumps..."
mysqldump --all-databases --single-transaction | gzip > /var/backups/mysql-all.sql.gz || \
    error_exit "MySQL dump failed"

# Create backup
log "Creating Borg archive..."
borg create \
    --verbose \
    --stats \
    --progress \
    --compression zstd,6 \
    --exclude-from /etc/borg/exclude-patterns.txt \
    "::$BACKUP_NAME" \
    /home \
    /etc \
    /var/www \
    /var/backups \
    /opt \
    /root 2>&1 | tee -a "$LOG_FILE"

if [ ${PIPESTATUS[0]} -ne 0 ]; then
    error_exit "Borg create failed"
fi

# Prune old backups
log "Pruning old archives..."
borg prune \
    --verbose \
    --list \
    --keep-daily=7 \
    --keep-weekly=4 \
    --keep-monthly=12 \
    2>&1 | tee -a "$LOG_FILE"

if [ ${PIPESTATUS[0]} -ne 0 ]; then
    error_exit "Borg prune failed"
fi

# Compact repository (free space from pruned archives)
log "Compacting repository..."
borg compact 2>&1 | tee -a "$LOG_FILE"

# Verify integrity (periodic check)
DAY_OF_MONTH=$(date +%d)
if [ "$DAY_OF_MONTH" == "01" ]; then
    log "Running monthly integrity check..."
    borg check --verify-data 2>&1 | tee -a "$LOG_FILE"
fi

log "Backup completed successfully: $BACKUP_NAME"

# Send success notification
echo "Backup completed successfully at $(date)" | \
    mail -s "Backup SUCCESS - $(hostname)" "$ADMIN_EMAIL"

exit 0

Make executable:

sudo chmod +x /usr/local/bin/borg-backup.sh

Managing Archives and Retention

Listing Archives

View all backups in repository:

# List all archives
borg list /backup/borg-repo

# Output:
# backup-20260105-020000    Sat, 2026-01-05 02:00:00
# backup-20260106-020000    Sun, 2026-01-06 02:00:00
# backup-20260107-020000    Mon, 2026-01-07 02:00:00

List files in specific archive:

# List all files
borg list /backup/borg-repo::backup-20260111

# List specific directory
borg list /backup/borg-repo::backup-20260111 | grep '/etc/'

# List with details
borg list --short /backup/borg-repo::backup-20260111 /home/user/

Repository Information

Get repository statistics:

# Repository info
borg info /backup/borg-repo

# Output:
# Repository ID: abc123...
# Location: /backup/borg-repo
# Encrypted: Yes (repokey)
# Cache: /root/.cache/borg/abc123
# Security dir: /root/.config/borg/security/abc123
#                        Original size      Compressed size    Deduplicated size
# All archives:              150.23 GB             95.87 GB               12.34 GB

Archive-specific info:

# Info for specific archive
borg info /backup/borg-repo::backup-20260111

Pruning Archives

Implement retention policies automatically:

Prune command syntax:

borg prune \
    --keep-daily=7 \
    --keep-weekly=4 \
    --keep-monthly=12 \
    --keep-yearly=2 \
    /backup/borg-repo

Retention options:

  • --keep-hourly=N: Keep N hourly backups
  • --keep-daily=N: Keep N daily backups
  • --keep-weekly=N: Keep N weekly backups (last backup of each week)
  • --keep-monthly=N: Keep N monthly backups (last backup of each month)
  • --keep-yearly=N: Keep N yearly backups (last backup of each year)

Example: GFS rotation:

borg prune \
    --list \
    --show-rc \
    --keep-daily=7 \
    --keep-weekly=4 \
    --keep-monthly=6 \
    --keep-yearly=2 \
    /backup/borg-repo

Dry-run before actual pruning:

# Test pruning without deleting
borg prune \
    --dry-run \
    --list \
    --keep-daily=7 \
    --keep-weekly=4 \
    /backup/borg-repo

Compacting Repository

After pruning, reclaim space:

# Compact repository (Borg 1.2+)
borg compact /backup/borg-repo

# Older versions: use
borg prune --keep-daily=7 /backup/borg-repo
# Space is automatically reclaimed

Deleting Specific Archives

Remove individual archives:

# Delete specific archive
borg delete /backup/borg-repo::backup-20260105

# Delete multiple archives
borg delete \
    /backup/borg-repo::backup-20260105 \
    /backup/borg-repo::backup-20260106

# Delete entire repository (DANGEROUS!)
borg delete /backup/borg-repo

Restoration Procedures

Mounting Archives

Mount backup as read-only filesystem for browsing:

# Create mount point
mkdir -p /mnt/borg-mount

# Mount latest archive
LATEST=$(borg list /backup/borg-repo | tail -1 | cut -d' ' -f1)
borg mount /backup/borg-repo::$LATEST /mnt/borg-mount

# Browse backup
ls -la /mnt/borg-mount/home/user/

# Unmount when done
borg umount /mnt/borg-mount

Mount all archives:

# Mount entire repository (all archives)
borg mount /backup/borg-repo /mnt/borg-mount

# Each archive appears as subdirectory
ls /mnt/borg-mount/
# backup-20260105-020000/
# backup-20260106-020000/
# backup-20260111-020000/

# Browse specific archive
ls /mnt/borg-mount/backup-20260111-020000/home/

# Unmount
borg umount /mnt/borg-mount

Extracting Files

Restore files from archives:

Extract entire archive:

# Extract to current directory
borg extract /backup/borg-repo::backup-20260111

# Extract to specific location
cd /restore-location
borg extract /backup/borg-repo::backup-20260111

Extract specific files/directories:

# Extract single file
borg extract /backup/borg-repo::backup-20260111 home/user/document.txt

# Extract directory
borg extract /backup/borg-repo::backup-20260111 etc/

# Extract multiple paths
borg extract /backup/borg-repo::backup-20260111 \
    home/user/ \
    etc/nginx/ \
    var/www/

Extract with different paths:

# Strip leading path components
borg extract --strip-components=2 \
    /backup/borg-repo::backup-20260111 \
    home/user/documents/
# Results in: documents/ in current directory

Complete System Restoration

Restore entire system after disaster:

# Boot from live USB/rescue system

# Partition and format disks
parted /dev/sda mklabel gpt
parted /dev/sda mkpart primary ext4 1MiB 100%
mkfs.ext4 /dev/sda1

# Mount target filesystem
mount /dev/sda1 /mnt/target

# Initialize Borg (import key if needed)
export BORG_REPO='user@backup-server:/backup/borg-repo'
export BORG_PASSPHRASE='your-passphrase'

# Extract latest backup
cd /mnt/target
LATEST=$(borg list $BORG_REPO | tail -1 | cut -d' ' -f1)
borg extract "::$LATEST"

# Reinstall bootloader
mount --bind /dev /mnt/target/dev
mount --bind /proc /mnt/target/proc
mount --bind /sys /mnt/target/sys
chroot /mnt/target
grub-install /dev/sda
update-grub
exit

# Unmount and reboot
umount /mnt/target/dev /mnt/target/proc /mnt/target/sys
umount /mnt/target
reboot

Remote Backups

SSH-Based Remote Repositories

Backup to remote server over SSH:

Setup SSH authentication:

# Generate SSH key
ssh-keygen -t ed25519 -f ~/.ssh/borg-backup-key -N ""

# Copy to remote server
ssh-copy-id -i ~/.ssh/borg-backup-key.pub user@backup-server

# Test connection
ssh -i ~/.ssh/borg-backup-key user@backup-server "echo SSH OK"

Initialize remote repository:

export BORG_RSH='ssh -i ~/.ssh/borg-backup-key'
borg init --encryption=repokey user@backup-server:/backup/borg-repo

Create remote backup:

borg create \
    --compression zstd,6 \
    --exclude-from /etc/borg/exclude-patterns.txt \
    user@backup-server:/backup/borg-repo::backup-$(date +%Y%m%d) \
    /home /etc /var/www

Remote backup script:

#!/bin/bash
# /usr/local/bin/borg-remote-backup.sh

export BORG_REPO='user@backup-server:/backup/borg-repo'
export BORG_PASSPHRASE='your-secure-passphrase'
export BORG_RSH='ssh -i /root/.ssh/borg-backup-key'

borg create \
    --compression zstd,6 \
    --exclude-from /etc/borg/exclude-patterns.txt \
    "::backup-$(hostname)-$(date +%Y%m%d-%H%M%S)" \
    /home /etc /var/www /opt

borg prune \
    --keep-daily=7 \
    --keep-weekly=4 \
    --keep-monthly=12

Append-Only Repositories

Protect against ransomware by preventing deletion:

Initialize append-only repository:

# On backup server, create repository
borg init --encryption=repokey /backup/borg-repo

# Configure as append-only
borg config /backup/borg-repo append_only 1

Restrict SSH access (on backup server):

Edit ~/.ssh/authorized_keys:

command="borg serve --append-only --restrict-to-path /backup/borg-repo",restrict ssh-ed25519 AAAA...

This allows clients to:

  • Create new archives
  • List archives
  • Extract archives

But prevents:

  • Deleting archives
  • Modifying existing archives
  • Pruning

Pruning append-only repos (server-side only):

# On backup server (manual or scheduled)
borg prune --keep-daily=7 --keep-weekly=4 /backup/borg-repo

Automation and Scheduling

Systemd Timer Implementation

Create service file (/etc/systemd/system/borg-backup.service):

[Unit]
Description=BorgBackup Service
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/borg-backup.sh
User=root
Nice=19
IOSchedulingClass=2
IOSchedulingPriority=7

# Security hardening
PrivateTmp=yes
ProtectSystem=strict
ProtectHome=read-only
ReadWritePaths=/backup /var/log /var/backups

# Timeout after 6 hours
TimeoutSec=21600

[Install]
WantedBy=multi-user.target

Create timer file (/etc/systemd/system/borg-backup.timer):

[Unit]
Description=BorgBackup Daily Timer
Requires=borg-backup.service

[Timer]
OnCalendar=daily
OnCalendar=*-*-* 02:00:00
Persistent=true
RandomizedDelaySec=30min

[Install]
WantedBy=timers.target

Enable timer:

sudo systemctl daemon-reload
sudo systemctl enable --now borg-backup.timer
sudo systemctl list-timers borg-backup.timer

Cron-Based Scheduling

Alternative cron setup:

# Edit root crontab
sudo crontab -e

# Daily backup at 2 AM
0 2 * * * /usr/local/bin/borg-backup.sh >> /var/log/borg-cron.log 2>&1

Monitoring and Verification

Integrity Checking

Regular integrity verification:

# Quick check (metadata only)
borg check /backup/borg-repo

# Full check (verify data)
borg check --verify-data /backup/borg-repo

# Check specific archive
borg check /backup/borg-repo::backup-20260111

Automated monthly verification:

#!/bin/bash
# /usr/local/bin/borg-verify.sh

export BORG_REPO='/backup/borg-repo'
export BORG_PASSPHRASE='your-passphrase'

# Full verification
borg check --verify-data 2>&1 | tee /var/log/borg-verify.log

if [ ${PIPESTATUS[0]} -eq 0 ]; then
    echo "Repository verification successful" | \
        mail -s "Borg Verification OK" [email protected]
else
    echo "Repository verification FAILED" | \
        mail -s "Borg Verification FAILED" [email protected]
fi

Schedule monthly:

# First day of month at 3 AM
0 3 1 * * /usr/local/bin/borg-verify.sh

Backup Monitoring Script

#!/bin/bash
# /usr/local/bin/monitor-borg-backup.sh

export BORG_REPO='/backup/borg-repo'
export BORG_PASSPHRASE='your-passphrase'

MAX_AGE_HOURS=26
ADMIN_EMAIL="[email protected]"

# Get latest archive
LATEST=$(borg list --short "$BORG_REPO" | tail -1)

if [ -z "$LATEST" ]; then
    echo "ERROR: No archives found in repository" | \
        mail -s "Borg Monitoring ALERT" "$ADMIN_EMAIL"
    exit 1
fi

# Get archive creation time
ARCHIVE_TIME=$(borg info "::$LATEST" | grep "^Time" | grep "start" | awk '{print $4, $5, $6}')
ARCHIVE_EPOCH=$(date -d "$ARCHIVE_TIME" +%s 2>/dev/null || date -j -f "%Y-%m-%d %H:%M:%S" "$ARCHIVE_TIME" +%s)
CURRENT_EPOCH=$(date +%s)
AGE_HOURS=$(( (CURRENT_EPOCH - ARCHIVE_EPOCH) / 3600 ))

if [ $AGE_HOURS -gt $MAX_AGE_HOURS ]; then
    echo "WARNING: Latest backup is $AGE_HOURS hours old (>$MAX_AGE_HOURS)" | \
        mail -s "Borg Backup Age Alert" "$ADMIN_EMAIL"
    exit 1
else
    echo "OK: Latest backup ($LATEST) is $AGE_HOURS hours old"
    exit 0
fi

Real-World Implementation Scenarios

Scenario 1: Workstation Personal Backup

Requirements:

  • User home directory
  • Configuration files
  • Daily automated backups
  • 30-day retention

Setup:

# Initialize repository
borg init --encryption=repokey ~/backups/borg-repo

# Create backup script
cat > ~/bin/borg-backup.sh << 'EOF'
#!/bin/bash
export BORG_REPO="$HOME/backups/borg-repo"
export BORG_PASSPHRASE="my-secure-passphrase"

borg create \
    --compression zstd,6 \
    --exclude-from "$HOME/.config/borg/exclude.txt" \
    "::backup-$(date +%Y%m%d-%H%M%S)" \
    "$HOME"

borg prune --keep-daily=30
EOF

chmod +x ~/bin/borg-backup.sh

# Create exclude file
cat > ~/.config/borg/exclude.txt << 'EOF'
.cache/
Downloads/
.local/share/Trash/
*.tmp
node_modules/
EOF

# Schedule with cron
crontab -e
# Add: 0 12 * * * ~/bin/borg-backup.sh

Scenario 2: Web Server Production Backup

Requirements:

  • Multiple websites
  • Database dumps
  • Remote backup repository
  • Monitoring and alerts

Implementation:

#!/bin/bash
# /usr/local/bin/borg-production-backup.sh

set -e

export BORG_REPO='[email protected]:/backups/web-server'
export BORG_PASSPHRASE='strong-production-passphrase'
export BORG_RSH='ssh -i /root/.ssh/borg-key'

LOG="/var/log/borg-production.log"
ADMIN="[email protected]"

log() {
    echo "[$(date)] $*" | tee -a "$LOG"
}

# Pre-backup: database dumps
log "Creating database dumps"
mkdir -p /var/backups/db-dumps

mysqldump --all-databases --single-transaction \
    | gzip > /var/backups/db-dumps/mysql-all.sql.gz

sudo -u postgres pg_dumpall \
    | gzip > /var/backups/db-dumps/postgresql-all.sql.gz

# Create backup
log "Creating Borg archive"
borg create \
    --compression zstd,8 \
    --exclude-from /etc/borg/exclude.txt \
    --stats \
    "::backup-$(hostname)-$(date +%Y%m%d-%H%M%S)" \
    /var/www \
    /etc \
    /var/backups/db-dumps \
    /opt

# Prune old backups
log "Pruning old archives"
borg prune \
    --keep-hourly=24 \
    --keep-daily=7 \
    --keep-weekly=4 \
    --keep-monthly=12

# Verify
log "Verifying repository"
borg check --last 1

log "Backup completed successfully"
echo "Production backup completed" | mail -s "Backup Success" "$ADMIN"

Scenario 3: Multi-Server Centralized Backup

Requirements:

  • 10 application servers
  • Central backup server
  • Individual repositories per server
  • Consolidated monitoring

Central backup server setup:

# /backup/borg-repos/
# ├── server01/
# ├── server02/
# ├── server03/
# ...

Per-server backup script:

#!/bin/bash
# On each application server

HOSTNAME=$(hostname -s)
export BORG_REPO="backup-server:/backup/borg-repos/$HOSTNAME"
export BORG_PASSPHRASE="passphrase-for-$HOSTNAME"
export BORG_RSH='ssh -i /root/.ssh/borg-key'

borg create \
    --compression zstd,6 \
    "::backup-$(date +%Y%m%d-%H%M%S)" \
    /etc /home /var/www /opt

borg prune --keep-daily=7 --keep-weekly=4 --keep-monthly=6

Centralized monitoring (on backup server):

#!/bin/bash
# /usr/local/bin/monitor-all-backups.sh

REPOS_DIR="/backup/borg-repos"
MAX_AGE_HOURS=26

for repo in "$REPOS_DIR"/*; do
    if [ -d "$repo" ]; then
        server_name=$(basename "$repo")
        export BORG_REPO="$repo"

        # Get latest archive age
        latest=$(borg list --short "$BORG_REPO" 2>/dev/null | tail -1)

        if [ -z "$latest" ]; then
            echo "WARNING: $server_name has no backups"
        else
            echo "OK: $server_name latest backup: $latest"
        fi
    fi
done

Troubleshooting

Repository Locked

Symptom: Failed to create/acquire the lock

Cause: Previous backup didn't complete cleanly

Solution:

# Check for running borg processes
ps aux | grep borg

# If no processes, break lock
borg break-lock /backup/borg-repo

# If process exists, wait or kill it

Cache Sync Issues

Symptom: Cache is newer than repository

Solution:

# Delete cache
rm -rf ~/.cache/borg/

# Rebuild cache
borg list /backup/borg-repo

Out of Space During Backup

Symptom: No space left on device

Solutions:

# Check repository size
borg info /backup/borg-repo

# Prune aggressively
borg prune --keep-daily=3 /backup/borg-repo

# Compact repository
borg compact /backup/borg-repo

# Check and increase storage
df -h /backup

Conclusion

BorgBackup represents a modern, sophisticated approach to data protection, combining deduplication, compression, and encryption to deliver efficient, secure backups. Its content-defined chunking and global deduplication enable dramatic storage savings while maintaining complete backup histories spanning months or years.

Key takeaways:

  1. Initialize securely: Choose appropriate encryption mode and protect passphrases/keys carefully.

  2. Optimize configuration: Use appropriate compression algorithms and exclude patterns for your use case.

  3. Automate consistently: Implement systemd timers or cron jobs with robust error handling.

  4. Prune regularly: Maintain retention policies to balance history with storage consumption.

  5. Monitor actively: Verify backups complete successfully and run periodic integrity checks.

  6. Test restoration: Regular restoration drills ensure confidence in recovery capabilities.

  7. Secure properly: Use append-only mode, protect SSH keys, and encrypt repositories appropriately.

BorgBackup is particularly well-suited for environments with:

  • Frequent backups of large datasets with incremental changes
  • Need for long retention periods (months/years)
  • Security requirements necessitating encryption
  • Limited storage budgets benefiting from deduplication

Combined with proper planning, automation, monitoring, and the 3-2-1 backup rule (maintain Borg repositories locally, remotely, and on different media), BorgBackup provides enterprise-grade data protection suitable for everything from personal workstations to production infrastructure.