TL;DR — Quick Summary

Borgmatic automates encrypted, deduplicated BorgBackup on Linux servers. Configure YAML, schedule via systemd timers, and implement 3-2-1 backup strategy.

Borgmatic turns BorgBackup’s powerful but verbose CLI into a declarative YAML configuration — one config file drives encrypted, deduplicated, compressed backups with retention policies, consistency checks, database hooks, and monitoring notifications. This guide covers every step from installation to a production-ready 3-2-1 backup strategy with database dumps and healthcheck integration.

Prerequisites

  • Linux server (Ubuntu 20.04+, Debian 11+, RHEL 8+, or similar)
  • Python 3.8+ (for pip install) or access to apt/dnf/pacman
  • SSH access to a remote backup destination (for off-site backups)
  • Root or sudo access
  • Basic familiarity with YAML and systemd

BorgBackup Fundamentals

BorgBackup is a deduplicating backup program written in Python and C. Before Borgmatic makes sense, understand what Borg provides:

  • Content-defined chunking — Borg splits files into variable-size chunks based on content hashing, not fixed block sizes. A renamed or slightly modified large file deduplicates efficiently because most chunks are identical.
  • Deduplication — Each unique chunk is stored exactly once across all archives in a repository. A 100 GB server with mostly unchanged data takes only megabytes for subsequent backups.
  • Encryptionrepokey-blake2 mode stores an AES-256-CTR encrypted key in the repository, protected by your passphrase and authenticated with HMAC-SHA256 (BLAKE2b variant). Even a fully compromised remote server exposes no plaintext data.
  • Compressionlz4 (fastest, minimal CPU), zstd (balanced, recommended), or zlib/lzma (maximum ratio). zstd,3 is the modern default.
  • Append-only mode — Repositories can be locked so that even a compromised client can create new archives but cannot delete or modify existing ones — ransomware cannot destroy your backup history.

Step 1: Install BorgBackup and Borgmatic

Via pip (recommended — always latest version):

pip install --upgrade borgmatic

Via pipx (isolated environment):

pipx install borgmatic

Via apt (Ubuntu/Debian):

apt install borgmatic

Via Docker:

docker run --rm \
  -v /etc/borgmatic:/etc/borgmatic \
  -v /var/backup:/backup \
  ghcr.io/borgmatic-collective/borgmatic

Verify installation:

borgmatic --version
borg --version

Step 2: Configure Borgmatic

Generate a commented template:

mkdir -p /etc/borgmatic
borgmatic config generate --destination /etc/borgmatic/config.yaml

A minimal production config for a web server with database dumps and monitoring:

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

repositories:
  - path: /var/backup/local-borg
    label: local
  - path: ssh://backup@192.168.1.100/~/backups/webserver
    label: remote-lan
  - path: ssh://backup@offsite.example.com:22/~/backups/webserver
    label: remote-offsite

storage:
  encryption_passphrase: "your-long-random-passphrase-here"
  compression: "zstd,3"
  archive_name_format: "{hostname}-{now:%Y-%m-%dT%H:%M:%S}"
  checkpoint_interval: 1800

retention:
  keep_within: 3H
  keep_hourly: 24
  keep_daily: 7
  keep_weekly: 4
  keep_monthly: 6
  keep_yearly: 1

consistency:
  checks:
    - name: repository
      frequency: always
    - name: archives
      frequency: 2 weeks

postgresql_databases:
  - name: myapp_production
    username: postgres
    password: dbpassword
    format: custom

mysql_databases:
  - name: wordpress
    username: root
    options: "--single-transaction"

hooks:
  before_backup:
    - echo "Starting backup at $(date)"
  after_backup:
    - curl -fsS -m 10 --retry 5 https://hc-ping.com/your-uuid > /dev/null
  on_error:
    - echo "Backup FAILED at $(date)" | mail -s "Backup Error" admin@example.com

Key configuration fields:

FieldPurposeRecommended value
encryption_passphraseProtects repository key40+ random characters
compressionAlgorithm + levelzstd,3
keep_dailyDaily archives retained7
keep_weeklyWeekly archives retained4
keep_monthlyMonthly archives retained6
checkpoint_intervalSeconds between checkpoints1800

Step 3: Initialize the Repository

Initialize each repository before the first backup:

borgmatic init --encryption repokey-blake2

For an append-only remote repository (highly recommended for off-site security):

# On the backup server, edit ~/.ssh/authorized_keys:
command="borg serve --restrict-to-path /home/backup/backups --append-only",restrict ssh-rsa AAAA... client@webserver

# Then initialize normally from the client
borgmatic init --encryption repokey-blake2

Export and store your repository key offline — this is critical:

borg key export /var/backup/local-borg /root/borg-key-backup.txt
# Store this in a password manager AND a USB drive kept off-site

Step 4: Run and Schedule Backups

First backup (verbose to verify everything works):

borgmatic create --verbosity 1 --list --stats

Regular operations:

borgmatic          # create + prune + compact + check (full default run)
borgmatic create   # backup only
borgmatic prune    # apply retention policy, remove old archives
borgmatic compact  # reclaim freed space (Borg 1.2+ required)
borgmatic check    # verify repository and archive integrity

View archives:

borgmatic list
borgmatic info --archive latest

Step 5: Schedule with systemd Timer

Borgmatic ships a systemd service and timer unit. Enable them:

systemctl enable --now borgmatic.timer
systemctl status borgmatic.timer

The default timer runs daily at a random time within the maintenance window, preventing thundering-herd issues when many servers back up simultaneously. To customize timing, create a drop-in override:

# /etc/systemd/system/borgmatic.timer.d/override.conf
[Timer]
OnCalendar=
OnCalendar=*-*-* 02:30:00
RandomizedDelaySec=30min
systemctl daemon-reload
systemctl restart borgmatic.timer

Step 6: Restore Procedures

List available archives:

borgmatic list

Restore specific files or directories:

borgmatic extract \
  --archive webserver-2026-03-23T02:30:00 \
  --path /var/www/myapp \
  --destination /tmp/restore

Restore entire system to a different path:

borgmatic extract --archive latest --destination /mnt/restore

Restore a PostgreSQL database dump:

borgmatic restore --archive latest --database myapp_production

Browse an archive with FUSE mount:

borgmatic mount --archive latest --mount-point /mnt/borg
ls /mnt/borg
borgmatic umount --mount-point /mnt/borg

Monitoring Integration

Borgmatic’s hooks integrate with any monitoring system. The after_backup hook runs only on full success; on_error fires on any failure:

Healthchecks.io (recommended — simple and free):

hooks:
  after_backup:
    - curl -fsS https://hc-ping.com/your-project-uuid > /dev/null
  on_error:
    - curl -fsS https://hc-ping.com/your-project-uuid/fail > /dev/null

Cronitor:

hooks:
  after_backup:
    - curl -fsS "https://cronitor.link/p/YOUR_KEY/run" > /dev/null

ntfy (self-hosted push notifications):

hooks:
  on_error:
    - "curl -d 'Borgmatic backup failed on $(hostname)' https://ntfy.sh/your-topic"

Database Hook Details

Borgmatic coordinates database dumps with the backup to ensure a consistent snapshot:

postgresql_databases:
  - name: all          # dumps all databases via pg_dumpall
    username: postgres
    format: custom     # pg_dump custom format — supports parallel restore

mysql_databases:
  - name: all
    username: root
    password: rootpassword
    options: "--single-transaction"  # consistent InnoDB dump without table locks

sqlite_databases:
  - path: /var/lib/myapp/data.db
    name: myapp

Dumps are placed in a temporary directory, backed up by Borg into the archive, then deleted. Restore is: borgmatic restore --archive latest.


3-2-1 Strategy with Multiple Repositories

Borgmatic natively backs up to all configured repositories in one run:

RepositoryTypeLocationPurpose
localLocal disk/var/backup/borgFast restore
remote-lanSSHNAS on local LANSite redundancy
remote-offsiteSSH / BorgBase / HetznerDifferent datacenterDisaster recovery

With this config, every borgmatic run creates archives in all three locations. A disk failure, ransomware attack, or datacenter fire only destroys one copy. Popular remote targets: BorgBase (purpose-built Borg hosting), rsync.net, Hetzner Storage Box (SSH + append-only supported).


Borgmatic vs Alternatives

FeatureBorgmaticResticDuplicatiKopiaTarsnap
EngineBorgBackupOwnOwnOwnOwn
EncryptionAES-256-CTR+HMACAES-256-CTRAES-256AES-256-GCMAES-256-CTR
DeduplicationChunk-levelContent-addressedBlock-levelYesYes
Config formatYAMLCLI flagsGUI/XMLGUI/CLICLI
DB hooksNative (PG, MySQL, SQLite)External scriptsNoNoNo
Append-onlyYes (SSH server-side)NoNoNoNo
Remote targetsSSH, SFTP, BorgBaseS3, B2, SFTP, manyFTP, S3, WebDAVS3, B2, SFTPTarsnap cloud
Monitoring hooksNative before/after/errorExternalExternalExternalNo
ComplexityLow (YAML)Medium (CLI)Low (GUI)MediumLow

Gotchas and Edge Cases

  • Passphrase loss = permanent data loss — Store the passphrase in a password manager AND export the repo key to cold storage. There is no recovery without both.
  • compact is not automaticborgmatic compact reclaims disk space after pruning. Without it, usage grows even after old archives are removed.
  • SSH key required for remote repos — Add the client’s public key to the backup server’s ~/.ssh/authorized_keys with borg serve restrictions before initializing.
  • Clock skew causes errors — Borg requires both hosts’ clocks to be within 1 hour of each other. Use chrony or systemd-timesyncd.
  • Permissions matter — Run Borgmatic as root to back up system directories, or as the application user for application-only backups. Never mix.
  • First backup is slow — Deduplication only helps after the first run. All chunks must be read, hashed, compressed, and encrypted on the first pass.
  • exclude_patterns matter — Always exclude /proc, /sys, /dev, /run, /tmp, and large cache directories to avoid backing up pseudo-filesystems and ephemeral data.

Troubleshooting

ProblemSolution
Failed to create/acquire the lockPrevious run stuck; run borgmatic borg break-lock /path/to/repo
Repository is not a valid Borg repositoryWrong path or repo not initialized; run borgmatic init
Passphrase provided is incorrectVerify encryption_passphrase in config matches the passphrase used at init
Connection closed by remote hostSSH key not in authorized_keys or borg serve not configured on remote
No archives foundFirst backup not yet run; run borgmatic create
compact: repository does not support compactionBorg < 1.2 on repository server; upgrade BorgBackup

Summary

  • BorgBackup provides content-defined chunking, deduplication, AES-256-CTR encryption, lz4/zstd/zlib compression, and append-only mode.
  • Borgmatic wraps Borg in a single YAML config covering create, prune, compact, check, database hooks, and monitoring notifications.
  • systemd timer handles scheduling with RandomizedDelaySec to prevent load spikes across servers.
  • Database hooks (PostgreSQL pg_dump, MySQL mysqldump, SQLite) ensure consistent snapshots without stopping services.
  • 3-2-1 strategy — three copies, two media types, one off-site — is implemented by listing multiple repositories in one config.
  • Always test restores before you need them; borgmatic check verifies integrity but only a successful extract confirms restorability.