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.
- Encryption —
repokey-blake2mode 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. - Compression —
lz4(fastest, minimal CPU),zstd(balanced, recommended), orzlib/lzma(maximum ratio).zstd,3is 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:
| Field | Purpose | Recommended value |
|---|---|---|
encryption_passphrase | Protects repository key | 40+ random characters |
compression | Algorithm + level | zstd,3 |
keep_daily | Daily archives retained | 7 |
keep_weekly | Weekly archives retained | 4 |
keep_monthly | Monthly archives retained | 6 |
checkpoint_interval | Seconds between checkpoints | 1800 |
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:
| Repository | Type | Location | Purpose |
|---|---|---|---|
local | Local disk | /var/backup/borg | Fast restore |
remote-lan | SSH | NAS on local LAN | Site redundancy |
remote-offsite | SSH / BorgBase / Hetzner | Different datacenter | Disaster 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
| Feature | Borgmatic | Restic | Duplicati | Kopia | Tarsnap |
|---|---|---|---|---|---|
| Engine | BorgBackup | Own | Own | Own | Own |
| Encryption | AES-256-CTR+HMAC | AES-256-CTR | AES-256 | AES-256-GCM | AES-256-CTR |
| Deduplication | Chunk-level | Content-addressed | Block-level | Yes | Yes |
| Config format | YAML | CLI flags | GUI/XML | GUI/CLI | CLI |
| DB hooks | Native (PG, MySQL, SQLite) | External scripts | No | No | No |
| Append-only | Yes (SSH server-side) | No | No | No | No |
| Remote targets | SSH, SFTP, BorgBase | S3, B2, SFTP, many | FTP, S3, WebDAV | S3, B2, SFTP | Tarsnap cloud |
| Monitoring hooks | Native before/after/error | External | External | External | No |
| Complexity | Low (YAML) | Medium (CLI) | Low (GUI) | Medium | Low |
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 automatic —
borgmatic compactreclaims 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_keyswithborg serverestrictions before initializing. - Clock skew causes errors — Borg requires both hosts’ clocks to be within 1 hour of each other. Use
chronyorsystemd-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
| Problem | Solution |
|---|---|
Failed to create/acquire the lock | Previous run stuck; run borgmatic borg break-lock /path/to/repo |
Repository is not a valid Borg repository | Wrong path or repo not initialized; run borgmatic init |
Passphrase provided is incorrect | Verify encryption_passphrase in config matches the passphrase used at init |
Connection closed by remote host | SSH key not in authorized_keys or borg serve not configured on remote |
No archives found | First backup not yet run; run borgmatic create |
compact: repository does not support compaction | Borg < 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
RandomizedDelaySecto 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 checkverifies integrity but only a successful extract confirms restorability.