borgmatic im Docker-Container: automatisierte Server-Backups mit BorgBackup
borgmatic ist kein weiteres Backup-Programm, sondern eine deklarative Konfigurationsschicht über BorgBackup. Diese Anleitung zeigt den Betrieb im Docker-Container mit vollständiger compose.yaml, kommentierter Konfiguration, Datenbank-Hooks, Monitoring und einer tatsächlich durchgeführten Wiederherstellung samt Prüfsummenvergleich.

Wer Server sichert, kennt das Problem: Das eigentliche Backup-Programm ist schnell eingerichtet, aber drumherum wächst eine Sammlung selbstgeschriebener Shell-Skripte für Aufbewahrungsregeln, Datenbank-Dumps, Benachrichtigungen und Konsistenzprüfungen. Genau diese Schicht ersetzt borgmatic durch eine einzige YAML-Datei.
borgmatic ist kein eigenes Backup-Format und kein Konkurrent zu restic oder Kopia auf der Speicherebene. Es ist eine deklarative Steuerungsschicht über BorgBackup: Quellverzeichnisse, Repositories, Retention, Datenbank-Hooks, Monitoring-Anbindung und Prüfläufe stehen in einer Konfigurationsdatei, und ein einziger Befehl führt den kompletten Ablauf aus. Diese Anleitung zeigt den Betrieb im Docker-Container, getestet auf einem Linux-Host mit Docker 29.1.3.
Nutzen und Grenzen
Der Nutzen von borgmatic liegt nicht in der Deduplizierung oder Verschlüsselung, das leistet BorgBackup darunter. Der Nutzen liegt in der Reproduzierbarkeit: Die komplette Backup-Logik eines Servers ist versionierbarer Text, den man in ein Konfigurationsmanagement einchecken kann.
- Eine Datei statt vieler Skripte: Quellen, Ziele, Aufbewahrung, Ausschlüsse, Prüfungen und Benachrichtigungen liegen zusammen.
- Datenbank-Dumps integriert: PostgreSQL, MySQL beziehungsweise MariaDB, MongoDB und SQLite werden vor dem Backup gedumpt und laut offizieller Dokumentation direkt zu Borg gestreamt, ohne zusätzlichen Plattenplatz für die Dump-Datei.
- Prüfungen mit Intervall: Konsistenzprüfungen lassen sich mit einer Frequenz versehen, etwa alle zwei Wochen, ohne dass man dafür einen zweiten Cron-Eintrag pflegt.
- Monitoring eingebaut: Healthchecks.io, ntfy, Cronitor, Apprise und weitere Ziele sind als Konfigurationsabschnitt vorhanden, nicht als Bastellösung im Skript.
- Deduplizierung über Zeit: Borg dedupliziert blockbasiert, tägliche Vollsicherungen belegen dadurch nur den Änderungsanteil.
Die Grenzen sind ebenso deutlich und sollten vor der Entscheidung bekannt sein:
- Repository-Sperren: Ein Borg-Repository kann zu einem Zeitpunkt nur von einem Prozess beschrieben werden. Ein abgebrochener Lauf hinterlässt eine Sperre, die manuell gelöst werden muss.
- Kein paralleles Multi-Client-Backup in dasselbe Repository: Mehrere Server, die gleichzeitig in ein gemeinsames Repository schreiben, blockieren sich. Der übliche Weg ist ein Repository pro Client, was allerdings die Deduplizierung zwischen Clients aufhebt.
- Kein Objektspeicher direkt: Borg spricht lokale Pfade und SSH. S3 oder Backblaze B2 gehen nur über eine Zwischenschicht wie rclone mount, was restic und Kopia von Haus aus besser können.
- Geschwindigkeit bei sehr vielen kleinen Dateien: Borg ist solide, aber bei Millionen kleiner Dateien deutlich langsamer als bei wenigen großen.
- Passphrase-Verlust ist endgültig: Ohne Passphrase und Schlüssel ist ein verschlüsseltes Repository unwiederbringlich verloren.
Abgrenzung zu restic und Kopia
Alle drei Werkzeuge erledigen deduplizierte, verschlüsselte Backups. Sie unterscheiden sich in dem, was sie zusätzlich mitbringen und wohin sie schreiben können.
| Aspekt | borgmatic mit Borg | restic | Kopia |
|---|---|---|---|
| Rolle | Konfigurationsschicht über Borg | eigenständiges Backup-Programm | eigenständiges Programm mit GUI |
| Konfiguration | deklarative YAML-Datei | Kommandozeile plus eigene Skripte | Policy-Objekte im Repository |
| Objektspeicher S3 | nur indirekt über rclone | nativ | nativ |
| Datenbank-Dumps | eingebaute Hooks | selbst zu skripten | selbst zu skripten |
| Parallele Clients pro Repository | nicht gleichzeitig, Sperre | möglich | möglich |
| Monitoring-Anbindung | eingebaut, mehrere Dienste | über Exit-Code im Skript | teilweise über Server-Modus |
| Typischer Einsatz | Linux-Server mit Datenbanken | gemischte Umgebungen, Cloud-Ziele | Arbeitsplätze und Server mit GUI-Bedarf |
Die Faustregel: Wer nach S3 oder zu einem Cloud-Objektspeicher sichert, ist mit restic oder Kopia direkter unterwegs. Wer einen oder mehrere Linux-Server mit Datenbanken auf eigenen Speicher oder einen SSH-Zielserver sichert und die gesamte Logik als Konfiguration verwalten will, ist bei borgmatic richtig. Die Kopia-Anleitung zeigt den Vergleichsfall mit grafischer Oberfläche.
Voraussetzungen und Ressourcen
borgmatic ist genügsam. Der Test für diese Anleitung lief auf einem Host mit acht Gigabyte RAM, davon etwa sechs Gigabyte frei, und ohne AVX-Befehlssatzerweiterung der CPU. Das war kein Hindernis, Borg und borgmatic benötigen AVX nicht.
- CPU: ein Kern genügt für kleine Datenmengen, zwei Kerne sind für Kompression komfortabler.
- RAM: 512 Megabyte reichen für den Container im Leerlauf. Der Speicherbedarf beim Backup wächst mit der Anzahl der Dateien, nicht mit deren Größe, weil Borg einen Chunk-Index im Speicher hält.
- Plattenplatz: Das Image ist schlank. Der Platzbedarf des Repositories hängt vom Änderungsanteil ab, nicht von der Anzahl der Sicherungen.
- Architekturen: Das offizielle Container-Image unterstützt laut Projekt-README
linux/amd64undlinux/arm64, läuft also auch auf ARM-Servern und auf einem Raspberry Pi mit 64-Bit-System. - Dateisystem: Das Repository-Verzeichnis sollte auf einem Dateisystem liegen, das harte Links und erweiterte Attribute beherrscht. Netzlaufwerke per SMB sind für Borg-Repositories ungeeignet.
Geprüfter Versionsstand
Das Projekt borgmatic liegt unter github.com/borgmatic-collective/borgmatic, steht unter GPL-3.0 und ist aktiv gepflegt. Stand 19. September 2026, laut GitHub-API: 2327 Sterne, letzter Push am 18. September 2026, Repository nicht archiviert. Die aktuellste veröffentlichte Version laut GitHub-API ist 2.1.8, veröffentlicht am 18. September 2026.
Wichtig für die Praxis: Der Test wurde mit dem Tag latest des offiziellen Container-Images durchgeführt. Der Container meldete dabei borgmatic 2.1.7 und borg 1.4.5 auf Alpine Linux. Das Image hinkte der am Vortag veröffentlichten Version 2.1.8 also um eine Patch-Version hinterher. Das ist bei Container-Images normal, weil der Image-Build dem Upstream-Release nachläuft. Wer eine bestimmte Kombination benötigt, verwendet statt latest einen versionierten Tag der Form 2.x.x-1.x.x, der laut Projekt-README ein festes Paar aus borgmatic- und Borg-Version bezeichnet.
Verzeichnisstruktur und Mountpunkte
Bevor der Container startet, wird die Ablage festgelegt. Jeder Pfad hat einen Zweck, und jeder davon muss persistent sein, sonst geht bei einem Neustart des Containers entweder das Repository oder der Cache verloren.
# Basisverzeichnis fuer den Dienst anlegen
mkdir -p /opt/borgmatic
cd /opt/borgmatic
# Unterverzeichnisse fuer persistente Daten
mkdir -p data/repository
mkdir -p data/borgmatic.d
mkdir -p data/cache
mkdir -p data/config
mkdir -p data/state
mkdir -p data/ssh
# Rechte einschraenken, das Repository enthaelt alle Daten
chmod 700 data/repository
chmod 700 data/ssh
chmod 750 data/borgmatic.d
| Host-Pfad | Container-Pfad | Zweck |
|---|---|---|
./data/repository | /mnt/borg-repository | Das Borg-Repository mit allen Archiven |
./data/borgmatic.d | /etc/borgmatic.d | Konfigurationsdateien, alle YAML-Dateien darin werden gelesen |
./data/cache | /root/.cache/borg | Chunk-Index, beschleunigt Folgeläufe erheblich |
./data/config | /root/.config/borg | Bekannte Repositories und Sicherheitsmerkmale |
./data/state | /root/.local/state/borgmatic | Zeitstempel der letzten Prüfläufe für die Frequenzsteuerung |
./data/ssh | /root/.ssh | Schlüssel für entfernte Repositories per SSH |
| Quelldaten | /mnt/source | Die zu sichernden Daten, bewusst als :ro eingebunden |
Der Mount der Quelldaten als :ro ist kein Detail, sondern eine Sicherheitsmaßnahme. Ein Backup-Prozess hat keinen Grund, Produktivdaten zu verändern. Fällt der Cache-Mount weg, baut Borg den Chunk-Index bei jedem Lauf neu auf, was bei großen Repositories aus Minuten Stunden macht.
Vollständige compose.yaml
Diese Datei entspricht bis auf angepasste Pfade genau der im Test verwendeten Konfiguration. Sie startet den Container dauerhaft mit einem internen Cron-Zeitplan.
services:
borgmatic:
image: ghcr.io/borgmatic-collective/borgmatic:latest
container_name: borgmatic
hostname: borgmatic
environment:
- TZ=Europe/Berlin
# Passphrase niemals hier eintragen, sondern aus der .env ziehen
- BORG_PASSPHRASE=${BORG_PASSPHRASE}
# taeglich um 02:00 Uhr Containerzeit
- CRON=0 2 * * *
- CRON_COMMAND=borgmatic-start --stats -v 0 2>&1
volumes:
# Quelldaten ausschliesslich lesend einbinden
- /srv/daten:/mnt/source:ro
- ./data/repository:/mnt/borg-repository
- ./data/borgmatic.d:/etc/borgmatic.d
- ./data/cache:/root/.cache/borg
- ./data/config:/root/.config/borg
- ./data/state:/root/.local/state/borgmatic
- ./data/ssh:/root/.ssh
# Zielverzeichnis fuer Wiederherstellungstests
- ./restore:/mnt/restore
restart: unless-stopped
# genug Zeit, damit ein laufendes Backup sauber endet
stop_grace_period: 10m
Der Parameter stop_grace_period: 10m ist wichtig. Ohne ihn beendet Docker den Container nach zehn Sekunden hart, und ein laufendes Backup hinterlässt eine Repository-Sperre.
Die .env-Datei mit den Geheimnissen
Die Passphrase gehört nicht in die compose.yaml und erst recht nicht in die borgmatic-Konfiguration, weil beide Dateien typischerweise in einem Repository versioniert werden.
# Datei: /opt/borgmatic/.env
# Diese Datei niemals in ein Git-Repository einchecken
BORG_PASSPHRASE=HIER-EINE-LANGE-ZUFAELLIGE-PASSPHRASE-EINSETZEN
POSTGRES_PASSWORD=PLATZHALTER-DB-PASSWORT
MYSQL_ROOT_PASSWORD=PLATZHALTER-DB-PASSWORT
BORG_HEALTHCHECK_URL=https://hc-ping.com/BEISPIEL-UUID-HIER-EINSETZEN
NTFY_TOPIC=backup-meldungen-eindeutiger-name
# Rechte auf die Geheimnisdatei strikt setzen
chmod 600 /opt/borgmatic/.env
# Eine belastbare Passphrase erzeugen
openssl rand -base64 32
Umgang mit der Repository-Passphrase
Dieser Abschnitt entscheidet darüber, ob das Backup im Ernstfall etwas wert ist. Ein verschlüsseltes Borg-Repository ohne Passphrase ist ein Haufen Zufallsdaten, und niemand kann daran etwas ändern, auch das Projekt nicht.
- Niemals im Klartext in der YAML: Die borgmatic-Konfiguration wird gerne versioniert und kopiert. Die Passphrase gehört in die Umgebung oder in eine separate Datei.
- Getrennt vom Backup aufbewahren: Liegt die Passphrase auf demselben Server wie das Repository, schützt sie bei einem Totalverlust dieses Servers niemanden. Sie gehört in einen Passwortmanager und zusätzlich in Papierform in einen Safe.
- Schlüssel exportieren: Bei der Verschlüsselungsart
repokeyliegt der Schlüssel im Repository. Geht das Repository verloren, ist auch der Schlüssel weg. Borg weist beim Initialisieren ausdrücklich darauf hin, den Schlüssel zusätzlich zu exportieren.
Beim Initialisieren gab Borg im Test diese Warnung aus, sinngemäß auf Deutsch: Man benötigt sowohl Schlüssel als auch Passphrase, um auf das Repository zuzugreifen, und sollte den Schlüssel exportieren und an einem sicheren Ort ablegen.
# Schluessel aus dem Repository exportieren
docker compose exec borgmatic borg key export /mnt/borg-repository /root/.ssh/borg-key-backup
# Zusaetzlich als ausdruckbare Papierfassung
docker compose exec borgmatic borg key export --paper /mnt/borg-repository /root/.ssh/borg-key-papier.txt
Zur Frage, wie die Passphrase in den Prozess gelangt, ergab der Test ein klares Bild. Mit gesetztem BORG_PASSPHRASE funktionierten alle Aktionen. Ein Versuch, stattdessen die Variable BORG_PASSPHRASE_FILE mit einem Pfad auf eine Datei zu verwenden, scheiterte in der getesteten Borg-Version 1.4.5 mit der Meldung, es sei weder BORG_PASSPHRASE noch BORG_PASSCOMMAND gesetzt. Erfolgreich war dagegen der Weg über BORG_PASSCOMMAND:
# Selbst geprueft: Passphrase aus einer Datei ueber BORG_PASSCOMMAND lesen
# Die Datei liegt mit Rechten 600 ausserhalb des Konfigurationsverzeichnisses
docker compose exec borgmatic env -u BORG_PASSPHRASE BORG_PASSCOMMAND="cat /root/.ssh/passphrase.txt" borgmatic list
Wer die Passphrase dauerhaft per Datei bereitstellen will, setzt BORG_PASSCOMMAND in der compose.yaml und bindet die Passphrase-Datei als eigenes, schreibgeschütztes Volume ein. Das hält das Geheimnis aus der Prozessliste und aus der Umgebungsvariablen-Ausgabe von docker inspect heraus.
Die borgmatic-Konfigurationsdatei im Detail
Jetzt der Kern. Diese Datei liegt auf dem Host unter ./data/borgmatic.d/config.yaml und im Container unter /etc/borgmatic.d/config.yaml. borgmatic liest alle YAML-Dateien in diesem Verzeichnis, mehrere Dateien für mehrere Backup-Sätze sind also möglich.
# Welche Verzeichnisse gesichert werden
source_directories:
- /mnt/source
# Wohin gesichert wird, mehrere Eintraege sind moeglich
repositories:
- path: /mnt/borg-repository
label: lokal
# Feste Archivnamen, weil Container-Hostnamen wechseln koennen
archive_name_format: 'srv01-{now:%Y-%m-%d-%H%M%S}'
# Was nicht ins Backup gehoert
exclude_patterns:
- '*/node_modules'
- '*/.cache'
- '*.tmp'
# Kompression, zstd Stufe 3 ist ein guter Kompromiss
compression: zstd,3
# Nicht ueber Dateisystemgrenzen hinweg sichern
one_file_system: true
# Aufbewahrung, greift beim Befehl prune
keep_daily: 7
keep_weekly: 4
keep_monthly: 6
keep_yearly: 1
# Konsistenzpruefungen mit eigener Frequenz
checks:
- name: repository
frequency: 2 weeks
- name: archives
frequency: 1 month
# Datenbank-Dumps vor dem Backup, direkt zu Borg gestreamt
postgresql_databases:
- name: kundendb
hostname: postgres
username: postgres
password: ${POSTGRES_PASSWORD}
format: custom
mysql_databases:
- name: shopdb
hostname: mariadb
username: root
password: ${MYSQL_ROOT_PASSWORD}
# Hooks vor und nach dem Lauf
commands:
- before: everything
run:
- echo "Backup startet"
- after: everything
states: [finish]
run:
- echo "Backup erfolgreich"
# Monitoring per Healthchecks.io
healthchecks:
ping_url: ${BORG_HEALTHCHECK_URL}
# Zusaetzliche Push-Meldung bei Fehlern per ntfy
ntfy:
topic: ${NTFY_TOPIC}
server: https://ntfy.sh
fail:
title: Backup fehlgeschlagen
message: borgmatic meldet einen Fehler
priority: high
Diese vollständige Konfiguration inklusive Datenbank-Hooks, Kommandos, Healthchecks und ntfy wurde im Test mit borgmatic config validate geprüft und vom Container mit der Meldung All configuration files are valid akzeptiert. Die Datenbank-Hooks selbst wurden mangels angeschlossener Datenbanken im Testaufbau nicht ausgeführt, die Schreibweise entspricht der offiziellen Dokumentation.
Die wichtigsten Konfigurationsoptionen
| Option | Wirkung | Hinweis zur Praxis |
|---|---|---|
source_directories | Liste der zu sichernden Pfade | Container-Pfade eintragen, nicht Host-Pfade |
repositories | Ziel-Repositories mit Pfad und Bezeichnung | Mehrere Einträge sichern in mehrere Ziele nacheinander |
archive_name_format | Namensschema der Archive | Ohne festen Namen bricht Pruning, wenn der Container-Hostname wechselt |
exclude_patterns | Ausschlüsse per Muster | Caches und temporäre Dateien sparen viel Platz und Laufzeit |
compression | Kompressionsverfahren und Stufe | zstd,3 ist schnell, lz4 noch schneller bei weniger Ersparnis |
one_file_system | Bleibt auf einem Dateisystem | Verhindert versehentliches Sichern eingehängter Netzlaufwerke |
keep_daily | Anzahl täglicher Archive | Wirkt erst beim Befehl prune |
keep_weekly | Anzahl wöchentlicher Archive | Zusammen mit den anderen Regeln entsteht die Großvater-Vater-Sohn-Staffelung |
keep_monthly | Anzahl monatlicher Archive | Sechs Monate sind ein üblicher Ausgangswert |
checks | Art und Frequenz der Prüfläufe | archives liest alle Daten und dauert entsprechend lange |
postgresql_databases | Dump vor dem Backup | Format custom erlaubt selektives Zurückspielen |
mysql_databases | Dump für MySQL und MariaDB | Für MariaDB existiert zusätzlich ein eigener Abschnitt |
commands | Hooks vor und nach Aktionen | Geeignet, um Dienste kurz zu stoppen oder Anwendungsdumps zu erzeugen |
healthchecks | Ping-URL für Totmannschaltung | Meldet auch, wenn ein Lauf gar nicht erst startet |
Start, Initialisierung und erstes Backup
Alle folgenden Schritte wurden auf dem Testsystem tatsächlich ausgeführt. Die zitierten Ausgaben sind gekürzte Originalausgaben.
# Container im Hintergrund starten
cd /opt/borgmatic
docker compose up -d
# Laufenden Zustand pruefen
docker compose ps
# Startmeldungen ansehen
docker compose logs --tail=30
# Versionen im Container feststellen
docker compose exec borgmatic borgmatic --version
docker compose exec borgmatic borg --version
Im Test meldete docker compose ps den Status Up, und die Versionsabfragen ergaben 2.1.7 für borgmatic sowie borg 1.4.5. Danach folgt die Initialisierung des Repositories. Sie ist einmalig und erzeugt die Verschlüsselungsstruktur.
# Repository einmalig initialisieren
docker compose exec borgmatic borgmatic init --encryption repokey
# Erstes Backup mit Statistik erzeugen
docker compose exec borgmatic borgmatic create --verbosity 1 --stats
# Vorhandene Archive auflisten
docker compose exec borgmatic borgmatic list
# Details zum Repository und zum letzten Archiv
docker compose exec borgmatic borgmatic info
Das erste Backup lief im Test in 0,05 Sekunden durch und meldete fünf Dateien, 505 Byte Originalgröße und 638 Byte dedupliziert, abgeschlossen mit Successfully ran configuration file. Der Testdatensatz war bewusst klein, weil es um den Nachweis des Ablaufs ging, nicht um Durchsatzmessung.
Eine Besonderheit bei der Verschlüsselungsart: Die Vorgabe repokey legt den Schlüssel im Repository ab. Für lokale Repositories auf vertrauenswürdigem Speicher ist das üblich. Liegt das Repository bei einem fremden Anbieter, ist keyfile die bessere Wahl, weil der Schlüssel dann ausschließlich lokal liegt. Das Projekt-README empfiehlt für die Initialisierung repokey-blake2, das auf Systemen ohne Hardware-Beschleunigung für SHA-256 schneller arbeitet.
Konsistenzprüfung und Aufbewahrung
Ein Backup, das stillschweigend korrupt wird, ist gefährlicher als gar kein Backup, weil es falsche Sicherheit erzeugt. Borg kann das Repository und die Archive gegen Prüfsummen verifizieren.
# Konsistenzpruefung ausfuehren
docker compose exec borgmatic borgmatic check --verbosity 1
# Aufbewahrungsregeln anwenden und alte Archive entfernen
docker compose exec borgmatic borgmatic prune --verbosity 1 --stats
# Freigewordenen Platz tatsaechlich zurueckgeben
docker compose exec borgmatic borgmatic compact
Der Prüflauf gab im Test aus: Finished full repository check, no problems found und anschließend Archive consistency check complete, no problems found. Für das Retention-Verhalten wurden drei Archive erzeugt und danach prune aufgerufen. Die Ausgabe lautete Keeping 2 archives and 0 checkpoints, pruning 1 archives and 0 checkpoints. Das entspricht dem erwarteten Verhalten: Die Regel keep_daily: 7 bewahrt pro Kalendertag nur das jeweils jüngste Archiv auf, zusätzlich hält Borg das allerneueste Archiv. Mehrere Sicherungen am selben Tag werden bis auf diese reduziert.
Wichtig ist der Unterschied zwischen prune und compact. prune entfernt Archiveinträge, gibt aber nicht zwangsläufig Plattenplatz frei. Erst compact räumt die Segmentdateien auf. Wer nur prune laufen lässt, wundert sich über ein Repository, das trotz Aufräumen nicht schrumpft.
Wiederherstellung, der entscheidende Teil
Ein Backup, das nie wiederhergestellt wurde, ist kein Backup, sondern eine Vermutung. Deshalb ist dieser Abschnitt der wichtigste der Anleitung, und deshalb wurde er im Test vollständig durchgespielt.
Zuerst die vollständige Wiederherstellung des jüngsten Archivs in ein leeres Zielverzeichnis:
# Komplettes juengstes Archiv in ein leeres Verzeichnis zurueckholen
docker compose exec borgmatic borgmatic extract --archive latest --destination /mnt/restore --verbosity 1
Ein praktischer Hinweis aus dem Test: Der Versuch, den Archivnamen über eine verschachtelte Auswertung der Listenausgabe zu ermitteln, schlug fehl, weil die Ausgabe von borgmatic list zusätzlich die Repository-Bezeichnung enthält. Borg quittierte das mit Archive ... does not exist und Exit-Status 31. Der Schlüsselbegriff latest ist der robustere Weg, ein konkreter Archivname aus der Listenausgabe funktioniert ebenfalls.
Entscheidend ist die anschließende Überprüfung. Die Dateien wurden unterhalb des Zielverzeichnisses mit ihrem ursprünglichen Pfad abgelegt, also unter /mnt/restore/mnt/source/. Der Vergleich der SHA-256-Prüfsummen ergab exakt die Werte der Originaldateien vor dem Backup, für alle drei Testdateien einschließlich der Datei im Unterverzeichnis. Damit ist die Wiederherstellung nicht nur gelaufen, sondern inhaltlich Byte für Byte belegt.
# Pruefsummen der Originale vor dem Backup notieren
sha256sum /srv/daten/rechnung.txt /srv/daten/app.conf > /root/original.sha256
# Nach der Wiederherstellung im Container vergleichen
docker compose exec borgmatic sh -c 'cd /mnt/restore/mnt && sha256sum srv/daten/rechnung.txt srv/daten/app.conf'
Häufiger als die Komplettwiederherstellung ist der Fall, dass genau eine Datei zurückgeholt werden muss. Auch das wurde geprüft und funktionierte:
# Nur eine einzelne Datei zurueckholen
# Der Pfad wird ohne fuehrenden Schraegstrich angegeben
docker compose exec borgmatic borgmatic extract --archive latest --path mnt/source/rechnung.txt --destination /mnt/restore
Im Test landete genau diese eine Datei im Zielverzeichnis, mit unverändertem Inhalt. Der fehlende führende Schrägstrich beim Pfad ist keine Schlamperei, sondern notwendig, weil Borg Pfade im Archiv relativ speichert.
Ein dritter Weg ist das Einhängen eines Archivs als Dateisystem, um darin zu stöbern. Dieser Weg scheiterte im Testaufbau reproduzierbar mit Runtime Error: FUSE mount failed und Exit-Status 2, weil dem Container das Gerät /dev/fuse und die passenden Rechte fehlten. Wer das Mounten braucht, erweitert den Dienst in der compose.yaml:
services:
borgmatic:
# uebrige Einstellungen wie oben
devices:
- /dev/fuse:/dev/fuse
cap_add:
- SYS_ADMIN
security_opt:
- apparmor:unconfined
Diese Zusätze wurden im Test nicht verifiziert. Sie erweitern die Rechte des Containers spürbar, insbesondere SYS_ADMIN. Wer das Mounten nur gelegentlich braucht, fährt sicherer damit, stattdessen gezielt einzelne Pfade zu extrahieren und auf die erweiterten Rechte zu verzichten.
Restore-Test als feste Routine
Die Wiederherstellung einmal beim Einrichten zu testen genügt nicht. Konfigurationen ändern sich, Quellverzeichnisse kommen hinzu, Ausschlussmuster greifen versehentlich zu breit. Deshalb gehört ein wiederkehrender Restore-Test in den Betriebsplan.
- Monatlich: Eine zufällig ausgewählte Datei aus dem jüngsten Archiv zurückholen und die Prüfsumme gegen das Original vergleichen.
- Vierteljährlich: Ein vollständiges Archiv in ein separates Verzeichnis extrahieren und den Umfang gegen die Erwartung prüfen, also Anzahl der Dateien und Gesamtgröße.
- Jährlich oder nach größeren Änderungen: Wiederherstellung auf einem anderen Host, um zu belegen, dass Repository, Schlüssel und Passphrase unabhängig vom Originalsystem funktionieren.
- Bei jeder Datenbankänderung: Einen Dump aus dem Archiv tatsächlich in eine Testdatenbank einspielen. Ein vorhandener Dump ist noch kein einspielbarer Dump.
- Dokumentieren: Datum, geprüftes Archiv, Ergebnis und Dauer festhalten. Im Ernstfall weiß man dann, wie lange die Wiederherstellung dauern wird.
Die Anleitung zur Restore-Test-Routine beschreibt das Vorgehen unabhängig vom eingesetzten Werkzeug und lässt sich direkt auf borgmatic übertragen.
Für Datenbanken bringt borgmatic einen eigenen Wiederherstellungsbefehl mit, der den Dump aus dem Archiv holt und einspielt:
# Laut offizieller Dokumentation: Datenbank aus dem juengsten Archiv einspielen
docker compose exec borgmatic borgmatic restore --archive latest --database kundendb
Zeitsteuerung per Cron oder systemd-Timer
Für die Automatisierung gibt es drei Wege. Welcher passt, hängt davon ab, ob der Container dauerhaft laufen soll.
Weg eins, interner Cron im Container. Das offizielle Image bringt einen Scheduler mit. Über die Variable CRON wird ein Standard-Cron-Ausdruck gesetzt, laut Projekt-README läuft ohne Angabe täglich um 01:00 Uhr ein Lauf. Wichtig ist, dass der Cron-Befehl borgmatic-start verwendet, nicht borgmatic, weil sonst die Signalbehandlung beim Stoppen des Containers nicht greift.
environment:
- TZ=Europe/Berlin
# taeglich um 02:30 Uhr
- CRON=30 2 * * *
- CRON_COMMAND=borgmatic-start --stats -v 0 2>&1
Weg zwei, Cron auf dem Host. Der Container läuft dann nicht dauerhaft, sondern wird pro Lauf gestartet und danach entfernt. Das spart Ressourcen und vermeidet einen dauerhaft laufenden Prozess mit Zugriff auf alle Daten.
# Eintrag in der Crontab des Hosts, taeglich 02:30 Uhr
30 2 * * * cd /opt/borgmatic && /usr/bin/docker compose run --rm borgmatic borgmatic --stats -v 0
Weg drei, systemd-Timer auf dem Host. Gegenüber Cron bietet ein Timer bessere Protokollierung im Journal, eine zufällige Verzögerung gegen Lastspitzen und das Nachholen verpasster Läufe.
# Datei: /etc/systemd/system/borgmatic-backup.service
[Unit]
Description=borgmatic Backup im Container
After=docker.service
Requires=docker.service
[Service]
Type=oneshot
WorkingDirectory=/opt/borgmatic
ExecStart=/usr/bin/docker compose run --rm borgmatic borgmatic --stats -v 0
# Datei: /etc/systemd/system/borgmatic-backup.timer
[Unit]
Description=Taeglicher borgmatic Lauf
[Timer]
OnCalendar=*-*-* 02:30:00
RandomizedDelaySec=1800
Persistent=true
[Install]
WantedBy=timers.target
# Timer aktivieren und starten
systemctl daemon-reload
systemctl enable --now borgmatic-backup.timer
# Naechste Ausfuehrung pruefen
systemctl list-timers borgmatic-backup.timer
# Protokoll des letzten Laufs ansehen
journalctl -u borgmatic-backup.service -n 50
Healthcheck und Monitoring-Anbindung
Der gefährlichste Ausfall ist der stille. Ein Backup-Job, der seit sechs Wochen nicht mehr startet, meldet nichts, weil er nicht läuft. Dagegen hilft nur eine Totmannschaltung: Ein externer Dienst erwartet in einem Intervall ein Lebenszeichen und schlägt Alarm, wenn es ausbleibt.
borgmatic bringt dafür laut offizieller Dokumentation Integrationen für Healthchecks.io, Cronitor, Cronhub, PagerDuty, ntfy, Apprise, Uptime Kuma und Zabbix mit. Healthchecks.io pingt borgmatic laut Projekt-README automatisch bei Start, Erfolg und Fehler.
# Totmannschaltung, meldet auch ausbleibende Laeufe
healthchecks:
ping_url: ${BORG_HEALTHCHECK_URL}
# Zusaetzliche Push-Meldung bei Fehlern
ntfy:
topic: ${NTFY_TOPIC}
server: https://ntfy.sh
fail:
title: Backup fehlgeschlagen
message: borgmatic meldet einen Fehler
priority: high
# Alternative: Cronitor
cronitor:
ping_url: https://cronitor.link/p/BEISPIEL-KENNUNG
Auf der Ebene des Containers ergänzt ein einfacher Funktionstest das Bild. Die Konfigurationsprüfung ist schnell und liefert einen verwertbaren Exit-Code:
# Selbst geprueft: Konfiguration validieren
docker compose exec borgmatic borgmatic config validate --verbosity 1
Die Ausgabe lautete im Test All configuration files are valid. Wer ein zentrales Monitoring betreibt, kann darüber hinaus das Alter des jüngsten Archivs überwachen. Die Anleitung zu Healthchecks für Cronjob-Überwachung zeigt den Aufbau einer solchen Totmannschaltung im Detail.
Ransomware-Härtung, Append-only und Offsite
Ein lokales Repository auf demselben Server ist gegen Plattenausfall hilfreich und gegen Ransomware nutzlos. Verschlüsselt ein Angreifer den Server, erwischt er das Repository mit, weil der Backup-Prozess Schreibrechte darauf hat.
Borg bietet dafür den Append-only-Modus. Ein Repository, das über SSH mit dieser Einschränkung bereitgestellt wird, nimmt neue Daten an, erlaubt dem Client aber kein Löschen. Der Angreifer kann dann zwar Müll hinzufügen, aber die vorhandenen Archive nicht vernichten. Eingerichtet wird das auf dem Zielserver in der authorized_keys:
# Datei auf dem Backup-Zielserver: ~/.ssh/authorized_keys
# Der Client darf schreiben, aber nichts loeschen
command="borg serve --append-only --restrict-to-path /srv/borg/srv01",restrict ssh-ed25519 AAAAC3Nza...BEISPIEL client@srv01
Wichtig ist das Kleingedruckte: Der Append-only-Modus verhindert nicht, dass ein Angreifer mit Zugriff auf das Repository-Dateisystem selbst löscht. Er schützt nur gegen einen kompromittierten Client. Außerdem muss das Aufräumen alter Archive dann auf dem Zielserver erfolgen, nicht vom Client aus, was die Betriebsführung verkompliziert.
- Zwei Repositories eintragen: Ein lokales für schnelle Wiederherstellung, ein entferntes per SSH als Offsite-Kopie. borgmatic sichert nacheinander in beide.
- Getrennte Zugangsdaten: Der SSH-Schlüssel für das Offsite-Ziel gehört ausschließlich dem Backup-Prozess und hat keine Shell.
- Unveränderlichkeit auf Speicherebene: Wo möglich, ergänzt ein Dateisystem-Snapshot auf dem Zielserver den Append-only-Modus.
- Prüfläufe auf dem Ziel: Ein Offsite-Repository, das nie geprüft wird, ist eine Annahme.
Das Ganze ist die praktische Umsetzung der bekannten Regel: drei Kopien, zwei Medien, eine außer Haus. Die Anleitung zur 3-2-1-Strategie ordnet ein, wie die einzelnen Bausteine zusammenspielen.
Updates und Grenzen des Rollbacks
Ein Update des Containers ist unkompliziert, solange man den richtigen Zeitpunkt wählt und die Repository-Formatversion im Blick behält.
# Sicherstellen, dass gerade kein Backup laeuft
docker compose exec borgmatic borgmatic list
# Neues Image holen
docker compose pull
# Container mit neuem Image neu erstellen
docker compose up -d
# Version nach dem Update kontrollieren
docker compose exec borgmatic borgmatic --version
docker compose exec borgmatic borg --version
# Funktionsnachweis nach dem Update
docker compose exec borgmatic borgmatic config validate
docker compose exec borgmatic borgmatic check --verbosity 1
Die entscheidende Einschränkung beim Rollback: Ein Rückschritt auf ein älteres Image ist bei borgmatic selbst meist problemlos, bei einem Wechsel der Borg-Hauptversion aber nicht. Borg 2 verwendet ein neues Repository-Format, und ein einmal auf das neue Format gehobenes Repository lässt sich mit Borg 1.x nicht mehr lesen. Wer von der im Test vorgefundenen Kombination mit Borg 1.4.5 auf eine Borg-2-Variante wechselt, sollte das ausschließlich geplant tun, vorher eine Kopie des Repositories anlegen und die Migrationshinweise der Borg-Dokumentation lesen. Genau dafür sind die versionierten Image-Tags gedacht, die ein festes Paar aus borgmatic und Borg festschreiben.
Typische Fehler, Diagnose und Lösung
Die folgenden Punkte stammen teils aus dem Test, teils aus der Dokumentation. Wo im Test reproduziert, ist es vermerkt.
| Symptom | Ursache | Lösung |
|---|---|---|
Failed to create/acquire the lock | Vorheriger Lauf wurde hart abgebrochen | Nach Prüfung, dass kein Prozess läuft: borgmatic break-lock |
Cannot acquire a passphrase | Passphrase nicht in der Umgebung, im Test mit BORG_PASSPHRASE_FILE reproduziert | BORG_PASSPHRASE setzen oder BORG_PASSCOMMAND verwenden |
Archive ... does not exist, Exit 31 | Falsch ermittelter Archivname, im Test reproduziert | --archive latest nutzen oder Namen aus borgmatic list exakt übernehmen |
Runtime Error: FUSE mount failed, Exit 2 | /dev/fuse im Container nicht verfügbar, im Test reproduziert | Gerät und Rechte ergänzen oder stattdessen extract verwenden |
Permission denied beim Lesen der Quellen | Prozessnutzer im Container darf Quellpfad nicht lesen | Rechte auf dem Host prüfen, Mount-Pfade und Eigentümer kontrollieren |
| Wiederhergestellte Dateien nicht lesbar | Extrahierte Dateien gehören root, im Test beobachtet | Prüfung im Container vornehmen oder anschließend Eigentümer korrigieren |
No space left on device | Repository-Dateisystem voll | prune und danach zwingend compact, Aufbewahrung reduzieren |
| Pruning entfernt nichts | Archivname enthält wechselnden Hostnamen | Festes archive_name_format setzen |
| Repository schrumpft trotz prune nicht | compact wurde nie ausgeführt | borgmatic compact regelmäßig einplanen |
| Backup startet, aber niemand merkt Ausfälle | Keine Totmannschaltung eingerichtet | healthchecks oder cronitor konfigurieren |
Für die Fehlersuche ist die Ausführlichkeit steuerbar. Mit --verbosity 2 zeigt borgmatic die abgesetzten Borg-Befehle, was bei unklaren Fehlern am schnellsten zum Ziel führt.
# Sperre loesen, nur wenn sicher kein Backup laeuft
docker compose exec borgmatic borgmatic break-lock
# Maximale Ausfuehrlichkeit fuer die Fehlersuche
docker compose exec borgmatic borgmatic create --verbosity 2
# Protokoll des Containers ansehen
docker compose logs --tail=100 borgmatic
Saubere Deinstallation
Warnung: Die folgenden Schritte löschen unwiderruflich alle Sicherungen. Ein gelöschtes Borg-Repository ist nicht wiederherstellbar, es gibt keinen Papierkorb und keine Kulanzfrist. Bevor irgendetwas entfernt wird, muss zweifelsfrei feststehen, dass die darin enthaltenen Daten entweder nicht mehr benötigt werden oder an anderer Stelle vollständig und geprüft vorliegen. Geprüft bedeutet: eine Wiederherstellung wurde tatsächlich durchgeführt, nicht nur eine Kopie angelegt.
Der erste Schritt betrifft nur den Dienst und lässt die Daten unangetastet:
# Container stoppen und entfernen, Daten bleiben erhalten
cd /opt/borgmatic
docker compose down
# Zeitsteuerung auf dem Host deaktivieren, falls verwendet
systemctl disable --now borgmatic-backup.timer
Erst danach, und nur nach der oben genannten Prüfung, folgt das Entfernen der Daten. Ein Hinweis aus dem Test: Die vom Container erzeugten Dateien gehören root, ein unprivilegierter Nutzer scheitert beim Löschen mit Permission denied. Der saubere Weg führt daher über einen kurzlebigen Container oder über root.
# ACHTUNG: Loescht alle Sicherungen unwiderruflich
docker compose down -v
# Root-eigene Dateien ueber einen Wegwerf-Container entfernen
docker run --rm -v /opt/borgmatic:/ziel alpine sh -c 'rm -rf /ziel/data'
# Image entfernen
docker rmi ghcr.io/borgmatic-collective/borgmatic:latest
# Kontrolle, dass nichts zurueckbleibt
docker ps -a --filter name=borgmatic
Passende Anleitungen auf S-EDV
- restic-Backups unter Linux und Windows automatisieren: der direkte Vergleichsfall zu borgmatic, wenn das Ziel ein Objektspeicher ist und keine YAML-Konfigurationsschicht gebraucht wird.
- Eine Restore-Test-Routine etablieren: das systematische Vorgehen für wiederkehrende Wiederherstellungstests, direkt auf borgmatic übertragbar.
- Die 3-2-1-Backup-Strategie praktisch umsetzen: ordnet lokales Repository, Offsite-Kopie und Append-only-Härtung in ein Gesamtkonzept ein.
Quellen
- borgmatic, offizielle Projektdokumentation mit allen How-to-Anleitungen
- borgmatic auf GitHub, Quellcode und Release-Informationen zu Version 2.1.8
- docker-borgmatic, das offizielle Container-Image mit Scheduler und Konfigurationsbeispielen
- BorgBackup-Dokumentation zu Verschlüsselung, Append-only-Modus und Repository-Formaten