Files
nextcloud-borg-backup/Dokumentation.md
T

20 KiB

Betriebsdokumentation

Architektur und Befund

Das vorhandene Projekt liegt unter ~/localdev/nextcloud-borg-backup; Gitea: https://gitea.jr-it-services.de/johannes/nextcloud-borg-backup.

Am 26.10.2026 wurde das Ausbleiben täglicher Sicherungen untersucht. Der persistente User-Timer startete nach dem Login teilweise vor dem Desktop-rclone-Mount: am 26.10. Abbruch wegen leerer Quelle um 08:48:38, rclone-Start erst 08:48:54. Es gab keine Wiederholung. Zusätzlich waren ein FUSE-Abbruch am 15.10. und ein Verzeichnis-Cache von 72 Stunden konfiguriert. Das NAS war erreichbar; das letzte erfolgreiche Archiv stammte vom 23.10., nicht vom 13.10.

Version 2 entkoppelt die Sicherung vollständig vom Desktop-Mount:

Nextcloud WebDAV (rclone Nextcloud:)
   -> vollständige Inventur, Plausibilitätsprüfung
   -> rclone sync in privaten lokalen Zwischenstand
   -> Hash-/Downloadvergleich, unveränderte zweite Cloud-Inventur
   -> Borg create auf geprüftem NFS-Share
   -> Dateizahl/Bytezahl vergleichen, Archivdaten verifizieren, Repository prüfen
   -> atomare Erfolgsmarkierung
   -> Aufbewahrung und Kompaktierung

Die Cloud ist immer die Quelle. Keine Uploads oder Löschungen in Nextcloud. Nur der eigene lokale Zwischenstand wird mit rclone sync --delete-after an Cloud-Löschungen angepasst. Bei Fehlern entsteht kein als erfolgreich markiertes Archiv und es wird keine Aufbewahrungsbereinigung gestartet. Vorhandene Borg-Archive bleiben nutzbar.

Dateien und Zustände

Pfad Inhalt
~/.local/bin/nextcloud-borg-backup Bash-CLI für Backup und vorhandene Restore-Befehle
~/.local/libexec/nextcloud-borg-runner.py Python-Steuerung, keine externen Python-Pakete
~/.config/nextcloud-borg-backup/config Vertrauenswürdige Bash-Konfiguration
~/.config/nextcloud-borg-backup/passphrase Bestehende Borg-Passphrase, niemals regenerieren
~/.local/share/nextcloud-borg-backup/staging/ Unverschlüsselter, privater Cloud-Zwischenstand
~/.local/share/nextcloud-borg-backup/staging.owner.json Bindung des Zwischenstands an die Cloud-Quelle
~/.local/state/nextcloud-borg-backup/last-success.json Zeitpunkt, Archivname, Dateizahl, Bytezahl und tatsächlicher Staging-Pfad der bestätigten Sicherung
~/.local/state/nextcloud-borg-backup/last-attempt.json Laufstatus und Fehlerphase
~/.local/state/nextcloud-borg-backup/repository.json Bindung an die Borg-Repository-ID
~/.local/state/nextcloud-borg-backup/verified-inventory.json Zuletzt geprüfte Datei-Inventur mit Größen, Zeiten und Serverhashes
~/.local/state/nextcloud-borg-backup/logs/ Ablaufprotokolle, neue Protokolle nach 90 Tagen bereinigt

Vollständige Kindprozessausgaben stehen im systemd-Journal; die zusätzlichen Ablaufdateien enthalten Phasen und Status. Die Marker werden über temporäre Dateien, fsync und atomare Umbenennung geschrieben. Ein laufender Zwischenstand ist kein Wiederherstellungspunkt. Der letzte bestätigte Stand liegt im Borg-Repository.

Schutzmaßnahmen

  • Ausschließlich ein Lauf dank flock; auch manuelle Wartungsbefehle verwenden denselben Lock. Borg besitzt zusätzlich seinen eigenen Repository-Lock. Fremde Borg-Prozesse werden nicht durch automatisches break-lock übergangen.
  • Der NFS-Share muss exakt EXPECTED_NAS_SOURCE mit EXPECTED_NAS_FSTYPE entsprechen. Für die Workstation: thor:/volume1/NetBackup, nfs4. Autofs wird vor der Prüfung durch einen begrenzten Zugriff ausgelöst. Backup legt keine Verzeichnisse unter /net und kein Repository an.
  • Erste Quell-Plausibilisierung gegen das jüngste vorhandene Borg-Archiv; danach gegen den letzten bestätigten Stand. Rückgang von Dateizahl oder Bytezahl um mehr als MAX_SOURCE_DROP_PERCENT=20 führt zum Abbruch vor der Synchronisierung. Leere Quelle wird immer abgewiesen.
  • Bei konfiguriertem EXPECTED_STAGE_MOUNT/EXPECTED_STAGE_UUID werden der exakte lokale Mount und seine UUID vor der Anlage des Zwischenstands geprüft; ein fehlender oder fremder Datenträger führt zum Abbruch. Beide Werte müssen zusammen gesetzt werden.
  • Staging muss lokal sein, darf keine Symlinks/Mounts enthalten und darf sich nicht mit State, Repository oder ~/Nextcloud überschneiden. Ein bereits gefülltes, fremdes Verzeichnis wird nicht übernommen.
  • Hashvergleich, wenn jede Quelldatei MD5/SHA1 anbietet. Dateien ohne Serverhash werden vor dem Sync mit rclone copy --ignore-times erneut gelesen und anschließend zusätzlich per rclone check --download verglichen. Leere Dateien sind bereits durch Größe null eindeutig. Bei Zeilenumbrüchen in ungehashten Dateinamen erfolgt ein vollständiger Bytevergleich aller Dateien, weil rclones Dateiliste solche Namen nicht darstellen kann. Das kostet zusätzlich Übertragungszeit, vermeidet aber den unsicheren Rückfall auf reine Größenvergleiche.
  • Zusätzlich berechnet Python die lokalen SHA1-/MD5-Werte unabhängig von rclone und vergleicht jede verfügbare Cloud-Prüfsumme sowie die Dateigrößen.
  • Inventuren vor und nach Sync/Check müssen dieselben Dateinamen, Größen und Zeitstempel enthalten. Dateiveränderungen führen zu einem späteren neuen Versuch. Erscheinen oder verschwinden allein WebDAV-Prüfsummen, werden die betroffenen Dateien zusätzlich gegen die neu gemeldeten Hashes bzw. per Downloadvergleich geprüft; nur nach erfolgreichem Inhaltsvergleich darf die Sicherung weiterlaufen. Die Inventuren bleiben für die Diagnose privat gespeichert.
  • Borg-Warnungen zählen als Fehler. Jeder neue Archivstand durchläuft borg check --archives-only --verify-data --glob-archives <Archiv> und einen Repository-Check. Ältere Optionen FULL_CHECK_VERIFY_DATA, FULL_CHECK_INTERVAL_DAYS, REPOSITORY_CHECK_AFTER_BACKUP, SOURCE_DIR, ONE_FILE_SYSTEM und EXCLUDE_CACHES beeinflussen den neuen Backup-Pfad nicht mehr: jedes neue Archiv wird geprüft und alle Cloud-Dateien werden erfasst. Aktive alte Exclude-Regeln führen zu einem erklärenden Abbruch, statt unbemerkt Dateien auszulassen.
  • Erst nach dieser Prüfung wird der Erfolg gespeichert. Ein anschließender Wartungsfehler lässt das bestätigte Archiv gültig; der nächste Timerlauf versucht die Wartung erneut. --keep-within 4w --keep-last 7 schützt zusätzlich die letzten sieben Archivstände.
  • Einzelne Kindprozesse sind auf sechs Stunden begrenzt; systemd begrenzt den Gesamtlauf auf zwölf Stunden und beendet die gesamte Prozessgruppe. Keine endlose Wiederholung innerhalb eines Backup-Prozesses. Das nächste 15-Minuten-Fenster versucht erneut.

Zeitplanung und Warnungen

nextcloud-borg-backup.timer prüft alle 15 Minuten plus maximal 60 Sekunden Zufallsverzögerung, erstmals zwei Minuten nach Start des User Managers. Eine bestätigte Sicherung ist nach 24 Stunden wieder fällig. Persistent=true holt verpasste Kalendertermine nach. Bei einem aktiven Lauf startet systemd keinen zweiten gleichnamigen Service.

nextcloud-borg-health.timer prüft unabhängig stündlich sowie nach Start des User Managers das Alter. Nach 36 Stunden ohne bestätigten Stand meldet health Exitcode 2 und der Wächter versucht eine kritische Desktop-Benachrichtigung. Fehler beim Backup werden ebenfalls gemeldet; Benachrichtigungen werden sechs Stunden gedrosselt. Ohne Desktop-Benachrichtigungsdienst bleiben Journal und Exitstatus die Überwachung. Es wird keine E-Mail versandt.

Auf der Workstation ist loginctl show-user johannes -p Linger bereits yes. Der User Manager kann damit ohne Desktop-Anmeldung laufen. Voraussetzung bleiben eingeschaltete Workstation, erreichbare Cloud/NAS und ohne Dialog lesbare rclone-/Borg-Zugangsdaten. Bei ausgeschaltetem Rechner erfolgen weder Sicherung noch Warnung; beim nächsten Start wird nachgeholt.

nextcloud-borg-backup health
systemctl --user list-timers 'nextcloud-borg-*'
journalctl --user -u nextcloud-borg-backup.service --since today
journalctl --user -u nextcloud-borg-health.service --since today
cat ~/.local/state/nextcloud-borg-backup/last-attempt.json

Fehlerbehebung

NAS nicht erreichbar / falscher Mount: findmnt -T /net/thor/volume1/NetBackup/Nextcloud/borg-repo prüfen, autofs/NAS-Verbindung wiederherstellen. Niemals ein neues Repository an einem Ersatzpfad initialisieren. NFS-Hardmounts können bei Serverausfall im Kernel hängen; auch Prozess-Timeouts können einen ununterbrechbaren Kernelzugriff nicht sofort beenden.

Cloud ändert sich während des Laufs: Der nächste Timerlauf wiederholt. Bei dauernder hoher Änderungsrate ist eine ruhigere Zeit oder eine serverseitige Snapshot-Sicherung erforderlich. WebDAV liefert keinen atomaren Snapshot der gesamten Nextcloud. Lokale, noch nicht zur Cloud hochgeladene Desktop-Änderungen sind erst nach dem Upload Teil der Quelle.

Quellrückgang / Löschgrenze: Zuerst absichtliche Löschungen oder Umstrukturierungen prüfen und ältere Archive aufbewahren. Nur nach Prüfung MAX_SOURCE_DROP_PERCENT bzw. MAX_STAGE_DELETES in der privaten Konfiguration gezielt erhöhen, manuell sichern, anschließend Schutzgrenzen zurücksetzen. Diese Grenzen werden nicht automatisch aufgeweicht.

Staging zu groß / Speicher knapp: Keine Archive oder Staging-Daten während eines laufenden Backups löschen. Nach Stoppen des Services kann ausschließlich der Zwischenstand zusammen mit seiner Owner-Datei entfernt und später neu aufgebaut werden. Die Borg-Historie und Passphrase bleiben bestehen. Im Zweifel freien Speicher schaffen oder STAGING_DIR auf einen privaten lokalen Datenträger verschieben; die konservative Platzprüfung bleibt aktiv.

Repository-ID geändert: Erst klären, ob das richtige NAS und Repository vorliegen. repository.json nicht automatisch löschen. Bei bewusstem Repository-Wechsel State und Baseline nach Prüfung neu aufsetzen. Ein fehlendes oder beschädigtes State-JSON soll nicht still als Erfolg gelten.

Abbruch / Stromausfall: Ein unvollständiger Zwischenstand wird beim nächsten Lauf erneut synchronisiert. Ein Archiv vor der Erfolgsmarkierung gilt nicht als bestätigt und wird nicht als Anlass für Bereinigung verwendet. Borg-Checkpoint-Archive sind keine bestätigten Sicherungen.

Wiederherstellung und Notfall

nextcloud-borg-backup list
nextcloud-borg-backup restore "" "Dokumente/Beispiel.pdf" ~/Restore-Test
nextcloud-borg-backup restore nextcloud-2026-10-23_08-45-12 "Dokumente" ~/Restore-Test
nextcloud-borg-backup mount
nextcloud-borg-backup umount

Ziel ist standardmäßig ~/Nextcloud-Restore/<Archivname>, niemals automatisch die produktive Cloud. Wiederhergestellte Dateien prüfen und erst danach gezielt zurückkopieren.

Für ein neues System braucht man Borg 1.x, Repository und die originale Passphrase bzw. den exportierten Schlüssel. Sicherer zusätzlicher Export:

BORG_PASSCOMMAND='cat /sicherer/pfad/passphrase' borg key export /net/thor/volume1/NetBackup/Nextcloud/borg-repo /sicherer/pfad/borg-key.txt

Passphrase und exportierten Schlüssel unabhängig vom NAS und der Workstation sicher verwahren. Keine Zugangsdaten in Git, Logs oder Chat kopieren.

Tests und Installation

make check prüft Bash-Syntax, Python, alle vier systemd-Units und automatisierte Ausfallszenarien. Integrationstests verwenden echtes rclone mit lokalem Test-Remote sowie echtes Borg in temporären Verzeichnissen: Archiv erstellen, Daten prüfen, extrahieren und Bytevergleich. Sie verändern weder echte Cloud noch produktives Repository.

21 Tests prüfen außerdem leere/geschrumpfte Quelle, falsches NAS, fremdes/symlinkendes Staging, Netzfehler in Sync und Check, geänderte Cloud-Inventur, Repository-Austausch, konkurrierende Läufe, Timeout, Zeitrücksprung und Wartungswiederholung. Gleiche Dateigröße und gleicher Zeitstempel bei geändertem Inhalt werden im Integrationstest ausdrücklich abgedeckt.

Der Installer erhält private Konfiguration und Schlüssel, hält vorhandenen Backup-Dienst und Timer gemeinsam an, ersetzt Programme und Units atomar und startet die Timer neu. Der Update-Test prüft die Erhaltung von Konfiguration und Schlüssel sowie den Timer-Stopp. Eine fehlende Passphrase bei vorhandenem Repository führt zum Abbruch. Die Deinstallation stoppt Backup/Timer und entfernt Programme/Units; Daten, Schlüssel, State und Archive bleiben erhalten.

Grenzen

Die Sicherung schützt die durch das konfigurierte Nextcloud-Konto erreichbaren Dateien. Nextcloud-Datenbank, App-Konfiguration, Freigaberechte und serverseitige Versions-/Papierkorb-Metadaten sind kein Bestandteil dieser Datei-Sicherung. Ein vollständiges Nextcloud-Server-Backup bleibt separat erforderlich. Aktuelle Schäden oder Ransomware können als neue Dateiversion übernommen werden; die vierwöchige Historie und Mindestanzahl ersetzen kein unabhängiges unveränderbares Offsite-Backup.

Offizielle Referenzen

Einrichtung auf der Workstation am 26.10.2026

Bestehende Konfiguration und Passphrase wurden beibehalten. Die neuen Einstellungen wurden ausdrücklich ergänzt; die vorherige Konfiguration liegt privat unter ~/.config/nextcloud-borg-backup/config.pre-v2-20261026. Beide Timer sind aktiviert. Das vorhandene Linger blieb aktiv. Der Desktop-Mount und dessen Autostart wurden nicht umgebaut.

Für die Erstabnahme wurde der private Zwischenstand aus dem vorhandenen Archiv vom 23.10. vorgefüllt. Der anschließende direkte Cloud-Abgleich und sämtliche Prüfungen bleiben dadurch unverändert erforderlich; ein aus dem Altarchiv gelesener Stand gilt nicht automatisch als aktuelle Sicherung. Der beobachtete aktuelle Cloud-Bestand umfasst 8.218 Dateien mit 38.274.641.627 Bytes.

Erfolgreiche produktive Abnahme

Der vollständige Lauf am 26.10.2026 dauerte von 12:26:38 bis 13:01:15 Uhr MEZ und endete einschließlich Wartung erfolgreich. Verwendet wurden Borg 1.4.5, rclone 1.75.2 und Python 3.14.8.

Prüfung Ergebnis
Neues Archiv nextcloud-2026-10-26_12-48-01
Umfang 8.218 Dateien, 38.274.641.627 Bytes
Cloud-Inventur und Zwischenstand Dateipfade, Größen und Zeiten gleich; alle angebotenen Hashes lokal geprüft, Dateien ohne Hash per Downloadvergleich geprüft
Wechselnde WebDAV-Hash-Metadaten Im erfolgreichen Lauf sechs betroffene Dateien zusätzlich inhaltlich geprüft; keine Datenabweichung
Archivvergleich Dateizahl und Original-Bytezahl entsprechen exakt der Cloud-Inventur
Borg-Datenprüfung check --archives-only --verify-data erfolgreich
Repository-Prüfung check --repository-only erfolgreich
Wartung Prune und Compact erfolgreich; bestehende Archive innerhalb der Aufbewahrung erhalten
Wiederherstellungsprobe Drei Dateien (ODS, PDF, JPG) aus dem neuen NAS-Archiv extrahiert; alle SHA-256-Werte stimmen mit dem geprüften Zwischenstand überein
Health healthy: true, maintenance_pending: false
User-Service Result=success, ExecMainStatus=0
Wiederholungs-Timer Folgeläufe erkennen den aktuellen Erfolg und überspringen unnötige Übertragungen
Alterswächter Timer aktiviert und Health-Service erfolgreich ausgeführt
Automatisierte Tests 18 erfolgreich, zusätzlich Syntaxprüfung und Verifikation aller vier systemd-Units

Die Wiederherstellungsprobe ist eine Stichprobe von drei Dateien; die Borg-Datenprüfung erfasst den vollständigen neuen Archivstand. Die extrahierten Proben und deren Hash-Nachweis liegen privat unter ~/.local/state/nextcloud-borg-backup/restore-proof-20261026/ bzw. restore-proof.json. Dateinamen und private Inhalte wurden nicht in Git übernommen.

Nach dieser Abnahme wurde der endgültige Installer nochmals produktiv ausgeführt. Konfiguration und Passphrase blieben erhalten, installierte Programme entsprechen dem Repository. Die eigene rclone-Konfiguration wurde auf Dateirechte 0600 beschränkt. Der Zwischenstand belegt etwa 36 GiB; anschließend waren auf dem Home-Dateisystem noch etwa 124 GiB frei.

Zwischenstand auf der Datenplatte ab 27.10.2026

Die Workstation verwendet nun den tatsächlichen Pfad /mnt/data/johannes/nextcloud-borg-backup/staging. Der bisherige Home-Pfad ~/.local/share/nextcloud-borg-backup/staging und der zusätzliche sichtbare Zugang ~/Nextcloud-Zwischenstand sind Symlinks für den manuellen Zugriff. Auch staging.owner.json ist vom bisherigen Home-Ort auf die tatsächliche Owner-Datei auf der Datenplatte verlinkt. Im Backup ist ausschließlich der echte Pfad konfiguriert; die bestehende Ablehnung symlinkender Staging-Pfade bleibt aktiv.

EXPECTED_STAGE_MOUNT=/mnt/data und die fest eingetragene UUID der Datenplatte werden vor dem Anlegen des Zwischenstands und vor dem Sync geprüft. Fehlt die Platte oder liegt ein fremdes Dateisystem unter /mnt/data, bricht der Lauf ab, statt die Systemplatte mit einem neu angelegten Zwischenstand zu belegen. Die UUID wird nicht bei jedem Lauf dynamisch neu übernommen. Die Konfiguration ist privat; auf anderen Rechnern den tatsächlichen Mount und dessen UUID bewusst hinterlegen oder beide optionalen Schutzwerte leer lassen.

Der Umzug wurde bei angehaltenen Timern und mit Backup-Lock durchgeführt. 8.218 Dateien mit exakt 38.274.641.627 Bytes wurden kopiert, Quelldateien mit SHA-256 geprüft und neue Datenkopien unabhängig zurückgelesen. Identische Dateien sind auf Btrfs unabhängige Reflinks. Das unveränderte Original blieb nach der Symlink-Umschaltung zunächst erhalten. Die endgültige Freigabe zum Entfernen dieser alten lokalen Kopie ist an eine neue vollständige Sicherung am neuen Pfad gebunden. Schlüssel, NAS-Repository und dessen Identitätsbindung wurden nicht verlagert.

Die Programme sind gezielt installiert, ohne den normalen Installer während der Migration aufzurufen. Runner-Revision 4 und Wrapper entsprechen den Repository-Dateien. make check besteht mit 21 Tests, einschließlich echter lokaler rclone-/Borg-Sicherung und Restore sowie fehlendem/falschem Datenträger. Die drei neuen Mount-Tests prüfen insbesondere, dass vor einem Fehler kein Staging-Verzeichnis angelegt wird.

Produktive Umzugsabnahme

Am 27.10.2026 wurde vom neuen tatsächlichen Staging-Pfad eine vollständige Sicherung ausgeführt. Der Lauf von 18:05:41 bis 19:26:28 Uhr MEZ endete mit Status 0 und erfolgreicher Wartung:

Prüfung Ergebnis
Neues NAS-Archiv nextcloud-2026-10-27_18-50-45
Bestand 8.218 Dateien, 38.274.641.627 Originalbytes
Cloud-Abgleich und unabhängige lokale Hashes Erfolgreich; 230 Dateien ohne geeigneten Serverhash zusätzlich per Download verglichen
Wechselnde Hash-Metadaten 29 Dateien zusätzlich inhaltlich geprüft, keine Inhaltsabweichung
Archiv-Datenprüfung borg check --archives-only --verify-data --glob-archives <neues Archiv> erfolgreich
Repository und Wartung Repository-Check, Retention und Compact erfolgreich
Ursprünglicher Zwischenstand Erst nach erfolgreichem neuen Backup entfernt
Automatik und Zustand Beide Timer wieder active/waiting, health meldet healthy: true

Die private Ausgangskonfiguration, bisherigen Programme, Owner-Datei und Umzugs-/Prüfberichte sind unter ~/.local/state/archwork-storage-20261027/ gesichert. Keine dieser privaten Dateien gehört ins Repository. Die vorherige Konfiguration darf nicht blind zurückkopiert werden: Der alte Home-Pfad ist jetzt ein Symlink und wäre als Backup-Arbeitsverzeichnis absichtlich unzulässig. Für einen erneuten Umzug wieder den tatsächlichen Zielpfad konfigurieren, Owner-Datei und feste Datenträgeridentität passend setzen und vor Entfernen der alten Daten prüfen.