TL;DR — Quick Summary

Borgmatic automates encrypted, deduplicated BorgBackup for 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 production-ready 3-2-1 backup strategy on a Linux server.

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 gives you:

  • Deduplication — Borg splits files into variable-size chunks and stores each unique chunk once. 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. Even if the remote server is compromised, data is unreadable without the passphrase.
  • Compressionlz4 (fast), zstd (balanced), or lzma (max). zstd,3 is the modern default.
  • Append-only mode — Repositories can be set append-only so that even a compromised client cannot delete existing archives, only add new ones.

Step 1: Install BorgBackup and Borgmatic

Via pip (recommended — always latest version):

pip install --upgrade 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:

source_directories:
  - /etc
  - /var/www
  - /home
  - /var/lib/postgresql  # only if not using database hooks

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

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):

# 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 client — Borg will create an append-only repo
borgmatic init --encryption repokey-blake2

Export and store your repository key offline:

borg key export /var/backup/local-borg /root/borg-key-backup.txt
# Store this file in a password manager or offline USB — you need it if the repo moves

Step 4: Run Backups

First backup (verbose to verify):

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

Regular operations:

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

View archives:

borgmatic list
borgmatic list --archive latest
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:

# /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:

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:

borgmatic restore --archive latest --database myapp_production

Mount an archive for browsing:

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

Monitoring Hooks

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

Healthchecks.io:

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

Uptime Kuma (push monitor):

hooks:
  after_backup:
    - curl -fsS "https://uptime.example.com/api/push/MONITOR_KEY?status=up&msg=OK" > /dev/null

PagerDuty via curl:

hooks:
  on_error:
    - "curl -X POST https://events.pagerduty.com/v2/enqueue -H 'Content-Type: application/json' -d '{\"routing_key\":\"YOUR_KEY\",\"event_action\":\"trigger\",\"payload\":{\"summary\":\"Backup failed\",\"severity\":\"critical\"}}'"

Database Hooks

Borgmatic coordinates database dumps with the backup process to ensure consistency:

postgresql_databases:
  - name: all          # dumps all databases
    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 locking

Database dumps land in a temp directory, get backed up by Borg, then are removed. Restore is a single command: borgmatic restore --archive latest.


3-2-1 Strategy with Multiple Repositories

Borgmatic natively supports multiple repositories in one config — backups run to all of them in sequence:

RepositoryTypeLocationPurpose
localLocal disk/var/backup/borgFast restore
remote-lanSSHNAS on local LANSite redundancy
remote-offsiteSSHVPS in different datacenterDisaster recovery

With this config, every borgmatic run creates archives in all three locations. A disk failure, ransomware attack, or datacenter fire only affects one copy.


Comparison: Borgmatic vs Alternatives

FeatureBorgmaticResticDuplicatiKopiaBacula
BackendBorgBackupOwn engineOwn engineOwn engineOwn engine
EncryptionAES-256-CTRAES-256-CTRAES-256AES-256-GCMDES/AES
DeduplicationYes (chunk-level)Yes (content-addressed)Yes (block-level)YesNo
Config formatYAMLCLI flagsGUI/XMLGUI/CLIConfig files
DB hooksNative (PG, MySQL)External scriptsNoNoPlugin
Append-onlyYes (SSH server-side)NoNoNoNo
Monitoring hooksYes (before/after/error)ExternalExternalExternalYes
ComplexityLow (YAML)Medium (CLI)Low (GUI)MediumHigh
Remote targetsSSH, SFTPS3, B2, SFTP, manyFTP, S3, WebDAVS3, B2, SFTPLAN/WAN

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 space after pruning; without it, disk 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 clocks within 1 hour of each other. Use NTP (systemctl enable --now chronyc.service).
  • Permissions matter — Run Borgmatic as root to back up system directories, or as the application user for application-only backups.
  • First backup is slow — Deduplication only helps after the first run. Expect the initial backup to take proportionally longer.

Troubleshooting

ProblemSolution
Failed to create/acquire the lockPrevious run is 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 in passphrase file is incorrectWrong env var or config passphrase; verify encryption_passphrase matches init passphrase
Connection closed by remote hostSSH key not added or borg serve not in authorized_keys; check remote SSH config
No archives foundFirst backup not yet run; run borgmatic create
compact: error — repository does not support compactionBorg < 1.2; upgrade BorgBackup on the repository server

Summary

  • BorgBackup provides deduplication, AES-256 encryption, compression, and append-only mode.
  • Borgmatic wraps Borg in a single YAML config covering create, prune, compact, check, and hooks.
  • systemd timer handles scheduling with RandomizedDelaySec to prevent load spikes.
  • Database hooks ensure consistent PostgreSQL and MySQL dumps without stopping services.
  • 3-2-1 strategy — three copies, two media types, one off-site — implemented by listing multiple repositories.
  • Always test restores before you need them; borgmatic check verifies integrity but only a successful extract confirms restorability.