BorgBackup: Automated, Encrypted
Off-Site Backups for Linux

Most backup tools make you choose between simplicity and features. BorgBackup doesn't - it gives you content-addressed deduplication, zstd compression, and AES-256 encryption in a single command-line tool. Add borgmatic and you get fully automated backups with reliable retention policies.

Why BorgBackup?

The 3-2-1 backup rule (three copies, two different media types, one off-site) is well-known. The harder problem is implementing it reliably without paying a fortune or spending hours on configuration. BorgBackup solves the technical side elegantly:

  • Deduplication: Borg breaks files into variable-length chunks and only stores chunks that haven't been seen before. A 50 GB database that changes 100 MB daily uses roughly 100 MB of new storage per backup, not 50 GB.
  • Encryption: Repository contents are encrypted with AES-256-CTR before being written. Even if your backup destination is compromised, the data is unreadable without your passphrase.
  • Compression: Borg supports lz4 (fast), zstd (balanced), and zlib/lzma (maximum compression).
  • Integrity checking: Every chunk is stored with a checksum. borg check verifies the entire repository against these checksums.

Installation

# Debian / Ubuntu
apt install borgbackup

# Check version
borg --version

# Install borgmatic (backup automation wrapper)
pip3 install borgmatic
# or via apt on newer systems:
apt install borgmatic

For off-site backups, you'll need a remote destination: a second server, a rented storage server (Hetzner Storage Box works excellently with Borg), or any host where you can SSH. Install BorgBackup on the remote as well.

Initializing a Repository

A Borg repository is a directory (local or remote over SSH) that stores all your backup archives. Create one with borg init:

# Local repository (for testing)
borg init --encryption=repokey /mnt/backup/myserver

# Remote repository over SSH (recommended for off-site)
borg init --encryption=repokey-blake2 [email protected]:repos/myserver

You'll be prompted for a passphrase. Store it securely - in a password manager, on paper in a safe, or in a secrets manager. Without the passphrase, encrypted backups are unrecoverable. The repokey-blake2 encryption mode stores the repository key in the repository itself (encrypted by your passphrase), which simplifies key management.

# Export and save your repository key separately
borg key export [email protected]:repos/myserver /secure/location/borg-key-backup

Your First Backup

# Create an archive named with the current date and time
borg create \
  --compression zstd,3 \
  --stats \
  [email protected]:repos/myserver::'{hostname}-{now:%Y-%m-%dT%H:%M}' \
  /etc \
  /home \
  /var/www \
  /var/lib/postgresql \
  --exclude /var/www/*/node_modules \
  --exclude /home/*/.cache

The archive name uses Borg's format strings: {hostname} expands to your server's hostname and {now:%Y-%m-%dT%H:%M} to the current timestamp. The --stats flag prints deduplicated size information after the backup.

# List all archives in a repository
borg list [email protected]:repos/myserver

# List files in a specific archive
borg list [email protected]:repos/myserver::myserver-2025-04-28T03:00

Automated Backups with borgmatic

Running Borg manually is fine for testing, but production backups need automation and monitoring. borgmatic is a wrapper that handles scheduling, retention, consistency checks, and email notifications. Configure it in /etc/borgmatic/config.yaml:

repositories:
  - path: [email protected]:repos/myserver
    label: offsite

source_directories:
  - /etc
  - /home
  - /var/www
  - /var/lib/postgresql

exclude_patterns:
  - "*/node_modules"
  - "*/.cache"
  - "*/tmp"

compression: zstd,3

retention:
  keep_hourly: 24
  keep_daily: 7
  keep_weekly: 4
  keep_monthly: 6
  keep_yearly: 2

checks:
  - name: repository
    frequency: 2 weeks
  - name: archives
    frequency: 1 month

storage:
  encryption_passphrase: "your_secure_passphrase_here"
  # Better: use a passcommand to fetch from a secret store
  # encryption_passcommand: "cat /root/.borg-passphrase"

hooks:
  on_error:
    - echo "Backup failed on $(hostname)" | mail -s "Borg Backup FAILED" [email protected]

Run borgmatic manually to test: borgmatic --verbosity 1. Then set up a daily systemd timer or cron job:

# Create a systemd timer for daily backups at 3am
# /etc/systemd/system/borgmatic.timer
[Unit]
Description=Run borgmatic backup daily

[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true

[Install]
WantedBy=timers.target
systemctl enable --now borgmatic.timer

Restoring from Backup

The restore workflow is straightforward, but test it before you need it:

# Mount an archive to browse files
mkdir /mnt/restore
borg mount [email protected]:repos/myserver::myserver-2025-04-28T03:00 /mnt/restore

# Browse and copy files as needed
ls /mnt/restore/etc/
cp /mnt/restore/etc/nginx/nginx.conf /etc/nginx/nginx.conf

# Unmount when done
borg umount /mnt/restore
# Extract specific paths from an archive
borg extract \
  [email protected]:repos/myserver::myserver-2025-04-28T03:00 \
  etc/nginx \
  var/www/myapp
⚠️
Test your restores regularly. A backup that has never been tested is a backup of unknown quality. Schedule a monthly restore test where you extract a critical file or directory and verify its integrity. Automate it with a borgmatic check hook if possible.
Services Technologies Process Blog Get in Touch