Zum Hauptinhalt springen
S-EDV news
← Alle Anleitungen
📘 Anleitung Backup & Datensicherung 19.09.2026 · 13 min Lesezeit

borgmatic im Docker-Container: automatisierte Server-Backups mit BorgBackup

borgmatic steuert BorgBackup über eine YAML-Datei. Die Anleitung zeigt den Betrieb im Docker-Container mit festem Tag 2.2.0: Konfiguration, Datenbank-Hooks, erstes Backup, Prüfung, Wiederherstellung mit Prüfsummenvergleich und Monitoring.

Geprüft am 31.10.2026 · für borgmatic (docker-borgmatic) 2.2.0

WerbelinksMit * markierte Links sind Werbelinks: Bei einem Kauf erhalten wir eine Provision, der Preis bleibt gleich. Als Amazon-Partner verdiene ich an qualifizierten Verkäufen. Mehr dazu

Serverrack mit verkabelten Geräten neben Regal mit externen Festplatten, Vorhängeschloss und Grünpflanze

borgmatic steuert BorgBackup über eine einzige YAML-Datei: Quellen, Ziele, Aufbewahrung, Datenbank-Dumps, Konsistenzprüfungen und Benachrichtigungen. Es ist kein eigenes Backup-Format, sondern eine Steuerungsschicht über Borg. Diese Anleitung zeigt den Betrieb im offiziellen Container-Image von der Verzeichnisstruktur über das erste Archiv bis zur geprüften Wiederherstellung. Grundlage sind Tests mit borgmatic 2.1.7 (September 2026) und zuletzt am 31.10.2026 mit borgmatic 2.2.0 und Borg 1.4.5 auf einem Linux-Host mit Docker 29.8.2.

Voraussetzungen

  • Server: Linux-Host mit Docker Engine und Docker Compose v2, x86-64 oder ARM64 (laut README Images für linux/amd64 und linux/arm64, also auch Raspberry Pi mit 64-Bit-System).
  • CPU und RAM: 1 Kern und 512 MB RAM für kleine Datenmengen, 2 Kerne für Kompression. Der RAM-Bedarf wächst mit der Zahl der Dateien und Chunks, weil Borg den Index im Speicher hält. AVX ist nicht nötig.
  • Speicher: Das Repository wächst mit dem Änderungsanteil, nicht mit der Zahl der Sicherungen. Legen Sie es auf ein lokales Linux-Dateisystem (ext4, XFS, Btrfs), nicht auf eine SMB-Freigabe.
  • Offsite-Ziel (empfohlen): ein zweiter Server mit SSH-Zugang und installiertem Borg.
EckdatenWert
Imageghcr.io/borgmatic-collective/borgmatic:2.2.0 (borgmatic 2.2.0, Borg 1.4.5, Alpine)
Portskeine
Konfiguration./data/borgmatic.d nach /etc/borgmatic.d
Repository./data/repository nach /mnt/borg-repository
Quelldaten/srv/daten nach /mnt/source, nur lesend
Geheimnisse.env: BORG_PASSPHRASE, Datenbank-Passwörter, Ping-URL

borgmatic passt zu Linux-Servern mit Datenbanken, die auf eigenen Speicher oder per SSH sichern. Für S3 und andere Objektspeicher sind restic oder Kopia die bessere Wahl, weil Borg 1.x solche Ziele nur über eine Zwischenschicht wie rclone mount erreicht. Nur ein Prozess schreibt gleichzeitig in ein Repository, mehrere Server sichern deshalb in je ein eigenes.

Schritt 1: Verzeichnisse anlegen

Alle Pfade müssen persistent sein, sonst verlieren Sie beim Neustart Repository, Schlüssel oder Cache. Ohne Cache-Mount baut Borg den Chunk-Index bei jedem Lauf neu auf, bei großen Repositories stundenlang.

# 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-PfadContainer-PfadZweck
./data/repository/mnt/borg-repositoryBorg-Repository mit allen Archiven
./data/borgmatic.d/etc/borgmatic.dKonfiguration, alle YAML-Dateien darin werden gelesen
./data/cache/root/.cache/borgChunk-Index, beschleunigt Folgeläufe
./data/config/root/.config/borgBorg-Konfiguration und Keyfiles, laut README mitsichern
./data/state/root/.local/state/borgmaticZeitstempel der Prüfläufe für die Frequenzsteuerung
./data/ssh/root/.sshSchlüssel für entfernte Repositories

Verifizieren: ls -ld /opt/borgmatic/data/* zeigt sechs Verzeichnisse, repository und ssh mit drwx------.

Schritt 2: compose.yaml und .env anlegen

Docker Compose liest die .env nur für Platzhalter in der compose.yaml. In den Container gelangt eine Variable erst, wenn sie unter environment steht. Weil die borgmatic-Konfiguration in Schritt 3 neben der Passphrase auch Datenbank-Passwörter, Ping-URL und ntfy-Thema als ${…} liest, reicht die Datei diese Werte ebenfalls durch.

services:
  borgmatic:
    # feste Version: borgmatic 2.2.0 mit borg 1.4.5 (getestet)
    image: ghcr.io/borgmatic-collective/borgmatic:2.2.0
    container_name: borgmatic
    hostname: borgmatic
    environment:
      - TZ=Europe/Berlin
      # Passphrase niemals hier eintragen, sondern aus der .env ziehen
      - BORG_PASSPHRASE=${BORG_PASSPHRASE}
      # Variablen, die die borgmatic-Konfiguration per ${...} liest
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
      - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
      - BORG_HEALTHCHECK_URL=${BORG_HEALTHCHECK_URL}
      - NTFY_TOPIC=${NTFY_TOPIC}
      # 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

Ohne stop_grace_period: 10m beendet Docker den Container nach zehn Sekunden hart, ein laufendes Backup hinterlässt dann eine Repository-Sperre. Die Passphrase gehört weder in die compose.yaml noch in die borgmatic-Konfiguration, weil beide oft 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

Bewahren Sie die Passphrase zusätzlich im Passwortmanager und auf Papier auf. Ohne Passphrase und Schlüssel sind die Daten endgültig verloren.

Verifizieren: docker compose config zeigt unter environment alle fünf Variablen mit Werten statt leerer Einträge.

Schritt 3: borgmatic-Konfiguration schreiben

Die Datei liegt auf dem Host unter ./data/borgmatic.d/config.yaml. borgmatic liest alle YAML-Dateien im Verzeichnis, mehrere Backup-Sätze sind also möglich. Tragen Sie Container-Pfade ein, keine Host-Pfade.

# 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

Ohne festes archive_name_format findet Pruning alte Archive nicht mehr, wenn der Container-Hostname wechselt. keep_* wirkt erst bei prune, die Prüfung archives liest alle Daten und dauert entsprechend lange.

Die Datenbank-Hooks setzen voraus, dass die Container postgres und mariadb im selben Docker-Netzwerk erreichbar sind. Ohne Datenbanken entfernen Sie beide Abschnitte. Im Test mit postgres:17-alpine und mariadb:11.8 liefen beide Dumps.

Verifizieren: docker compose exec borgmatic borgmatic config validate meldet All configuration files are valid. Diese Prüfung löst ${…}-Variablen nicht auf. Ob alle Werte im Container ankommen, zeigt erst der erste Lauf in Schritt 4.

Schritt 4: Starten, initialisieren und erstes Backup

# 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

Danach initialisieren Sie das Repository einmalig und erzeugen das erste Archiv:

# 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

repokey legt den Schlüssel im Repository ab, üblich für eigenen Speicher. Bei fremden Anbietern ist keyfile besser, der Schlüssel liegt dann nur in ./data/config. Neuere borgmatic-Versionen nennen die Aktion repo-create, init funktionierte im Test weiterhin. Exportieren Sie den Schlüssel sofort, denn bei repokey ist er mit einem beschädigten Repository ebenfalls weg:

# Schluessel exportieren
# und die Dateien anschliessend vom Server auf ein anderes Medium kopieren
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

Verifizieren: docker compose ps zeigt Up, die Versionsabfragen liefern 2.2.0 und borg 1.4.5. Der Lauf endet mit Successfully ran configuration file, borgmatic list zeigt ein Archiv srv01-…, und unter data/ssh liegen beide Schlüsseldateien.

Schritt 5: Prüfen und alte Archive entfernen

# 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

prune entfernt nur Archiveinträge, Plattenplatz gibt erst compact frei. Im Test ergab prune mit drei Archiven eines Tages Keeping 2 archives …, pruning 1 archives: keep_daily behält je Kalendertag nur das jüngste Archiv.

Verifizieren: check meldet Finished full repository check, no problems found und Archive consistency check complete, no problems found.

Schritt 6: Wiederherstellung prüfen

Holen Sie das jüngste Archiv vollständig 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

Verwenden Sie latest oder den exakten Archivnamen. Im Test enthielt ein per Skript aus borgmatic list gelesener Name die Repository-Bezeichnung und führte zu Archive ... does not exist (Exit 31). Die Dateien landen mit ihrem Archivpfad unter /mnt/restore/mnt/source/ und gehören root. Vergleichen Sie deshalb die Prüfsummen im Container:

# Pruefsummen der Originale vor dem Backup notieren
cd /srv/daten && sha256sum rechnung.txt app.conf

# Nach der Wiederherstellung im Container vergleichen
docker compose exec borgmatic sh -c 'cd /mnt/restore/mnt/source && sha256sum rechnung.txt app.conf'

Eine einzelne Datei holen Sie ohne führenden Schrägstrich zurück, weil Borg Pfade im Archiv relativ speichert:

# 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

borgmatic restore spielt einen Datenbank-Dump aus dem Archiv ein und überschreibt dabei die Zieldatenbank. Richten Sie den Befehl deshalb zuerst auf eine Testinstanz:

# Laut offizieller Dokumentation: Datenbank aus dem juengsten Archiv einspielen
docker compose exec borgmatic borgmatic restore --archive latest --database kundendb

Planen Sie Restore-Tests regelmäßig ein, jährlich auch auf einem anderen Host mit Schlüssel und Passphrase aus der Ablage. Details: Restore-Test-Routine.

Verifizieren: Beide sha256sum-Ausgaben sind identisch. Im Test stimmten alle Testdateien überein, auch die einzeln zurückgeholte Datei.

Schritt 7: Zeitsteuerung und Monitoring

Die compose.yaml nutzt den internen Cron des Images. CRON nimmt einen Cron-Ausdruck, ohne Angabe läuft laut README täglich um 01:00 Uhr ein Backup. Verwenden Sie als Befehl borgmatic-start, sonst greift die Signalbehandlung beim Stoppen nicht.

Alternativ startet ein Host-Cron oder systemd-Timer (mit Persistent=true für verpasste Läufe) den Container nur pro Lauf. Setzen Sie dann CRON=false und entfernen Sie restart: unless-stopped, sonst laufen zwei Zeitpläne parallel.

# Alternative ohne internen Cron: Aufruf fuer Host-Cron oder systemd-Service (Type=oneshot)
cd /opt/borgmatic && /usr/bin/docker compose run --rm borgmatic borgmatic --stats -v 0

Ein Job, der nicht mehr startet, meldet nichts. Dagegen hilft eine Totmannschaltung: Healthchecks.io erwartet regelmäßig ein Lebenszeichen und alarmiert, wenn es ausbleibt. borgmatic pingt laut Dokumentation bei Start, Erfolg und Fehler. Cronitor, ntfy, Apprise und Uptime Kuma sind ebenfalls eingebaut. Den Aufbau zeigt die Anleitung zu Healthchecks für Cronjob-Überwachung.

Verifizieren: Nach dem nächsten geplanten Lauf zeigt Healthchecks.io den Check als „up“.

Schritt 8: Offsite-Kopie und Updates

Ein lokales Repository schützt nicht gegen Ransomware auf demselben Server. Tragen Sie unter repositories zusätzlich ein SSH-Ziel ein, borgmatic sichert dann nacheinander in beide. Im Append-only-Modus nimmt das Ziel neue Daten an, der Client kann aber keine Archive löschen:

# 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

Das schützt gegen einen kompromittierten Client, nicht gegen Zugriff auf das Dateisystem des Zielservers. prune und compact führen Sie dann auf dem Zielserver aus. Die Anleitung zur 3-2-1-Strategie ordnet die Bausteine ein.

Für ein Update erhöhen Sie den Image-Tag in der compose.yaml, während kein Backup läuft. Neuere Tags finden Sie in der Container-Registry, lesen Sie vorher die Release Notes. Laut README gibt es zusätzlich Tags der Form 2.x.x-1.x.x für ein festes Paar aus borgmatic- und Borg-Version.

# Sicherstellen, dass gerade kein Backup laeuft (keine borg-Prozesse)
docker compose exec borgmatic ps

# Nach Aenderung des Tags neues Image holen
docker compose pull

# Container mit neuem Image neu erstellen
docker compose up -d

# Version und Funktion nach dem Update kontrollieren
docker compose exec borgmatic borg --version
docker compose exec borgmatic borgmatic check --verbosity 1

Ein Wechsel der Borg-Hauptversion ist kein Routine-Update: Borg 2 verwendet ein neues Repository-Format, das Borg 1.x nicht liest. Wechseln Sie nur geplant, mit Kopie des Repositories und nach den Migrationshinweisen der Borg-Dokumentation.

Update von 2.1.10 auf 2.2.0: Laut Release Notes bleibt die Konfiguration kompatibel. 2.2.0 bringt einen Hook tarballs, der Tar-Archive (etwa VM-Backups) mit voller Deduplizierung ihres Inhalts sichert, behebt unter anderem ein Hängen bei Datenbank-Dumps mit viel Ausgabe sowie fehlende Cache-Treffer der ZFS-, LVM- und Btrfs-Hooks und tauscht im vorkompilierten Programm vertrauenswürdige Zertifikate der kompromittierten Zertifizierungsstelle eMudhra aus. Python 3.10 wird nicht mehr unterstützt; das betrifft nur Installationen außerhalb des Containers. Im Test am 31.10.2026 lief das Update von 2.1.10 auf 2.2.0 mit derselben compose.yaml: Das bestehende Archiv blieb sichtbar, ein weiteres Backup und check liefen mit Successfully ran configuration file durch, die Wiederherstellung lieferte identische Prüfsummen, und der Cron-Eintrag aus CRON war unverändert.

Verifizieren: borg --version zeigt nach dem Update weiterhin borg 1.x, check meldet keine Probleme.

Grundlagen zum Betrieb finden Sie in Docker Compose unter Linux: Grundlage für Selfhosting, Docker Compose absichern: Secrets, Healthchecks, Non-Root, Docker-Container automatisch aktualisieren: Diun, WUD und Renovate im Vergleich und Linux-Server absichern mit UFW und Fail2ban.

Typische Fehler

SymptomUrsacheLösung
Failed to create/acquire the lockVorheriger Lauf wurde hart abgebrochenNach Prüfung, dass kein Prozess läuft: borgmatic break-lock
Cannot acquire a passphrasePassphrase nicht in der Umgebung des Containers, im Test mit per exec gesetztem BORG_PASSPHRASE_FILE reproduziertBORG_PASSPHRASE oder BORG_PASSPHRASE_FILE in der compose.yaml setzen, für Einzelaufrufe BORG_PASSCOMMAND
Cannot find variable … in environmentDie Konfiguration nutzt ${…}, die Variable steht aber nur in der .env und nicht unter environmentVariable in der compose.yaml durchreichen, Container mit docker compose up -d neu erstellen
Archive ... does not exist, Exit 31Falsch ermittelter Archivname, im Test reproduziert--archive latest nutzen oder Namen exakt übernehmen
Runtime Error: FUSE mount failed, Exit 2/dev/fuse im Container nicht verfügbar, im Test reproduziertextract verwenden oder laut README Gerät /dev/fuse, SYS_ADMIN und apparmor:unconfined in einer eigenen docker-compose.restore.yml ergänzen
Wiederhergestellte Dateien nicht lesbarExtrahierte Dateien gehören root, im Test beobachtetIm Container prüfen oder Eigentümer anschließend korrigieren
Pruning entfernt nichtsArchivname enthält wechselnden HostnamenFestes archive_name_format setzen
Repository schrumpft trotz prune nichtcompact wurde nie ausgeführtborgmatic compact regelmäßig einplanen
Healthchecks error: 400 Client Error: Bad RequestBORG_HEALTHCHECK_URL enthält noch den Platzhalter, im Test reproduziert; das Backup läuft weiterEchte Ping-URL eintragen, docker compose up -d

Im Test funktionierte für einen einzelnen Aufruf das Lesen der Passphrase aus einer Datei über BORG_PASSCOMMAND. Mit --verbosity 2 zeigt borgmatic die abgesetzten Borg-Befehle:

# 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

# Maximale Ausfuehrlichkeit fuer die Fehlersuche
docker compose exec borgmatic borgmatic create --verbosity 2

Häufige Fragen

borgmatic oder restic?

borgmatic für Linux-Server mit Datenbanken und eigenem oder SSH-Ziel, restic für S3-Objektspeicher und mehrere gleichzeitig schreibende Clients.

Wie entfernen Sie borgmatic wieder?

docker compose down entfernt nur den Container, die Daten bleiben. Die Dateien unter data gehören root, löschen Sie sie mit sudo und nur, wenn die Sicherungen an anderer Stelle vorliegen und dort erfolgreich wiederhergestellt wurden. docker compose down -v löscht hier nichts, weil nur Bind-Mounts verwendet werden.

Lässt sich ein Archiv wie ein Laufwerk einhängen?

Ja, mit borgmatic mount. Der Container braucht dafür FUSE und SYS_ADMIN, was seine Rechte erheblich erweitert. Für gelegentliche Wiederherstellungen ist extract die sicherere Wahl.

Fazit

Mit borgmatic im Container wird die Backup-Logik eines Linux-Servers zu einer versionierbaren YAML-Datei. Im Test liefen Initialisierung, Backup, Prüfung, Aufbewahrung und Wiederherstellung mit identischen Prüfsummen. Entscheidend für den Betrieb sind eine fest gepinnte Version, die Passphrase getrennt vom Server, eine Offsite-Kopie im Append-only-Modus und Restore-Tests als feste Routine.

Weiterführende Anleitungen und Quellen

borgmaticBorgBackupDockerBackupLinuxAutomatisierungWiederherstellung