Files
app-backup/UPDATE_ANLEITUNG.md
T

15 KiB

Automatisches Update-Paket

Auf dem Arbeitsplatz die gelieferte .run-Datei und ihre .sha256-Datei per SCP auf den Server übertragen. Auf dem Server im selben Verzeichnis prüfen/starten:

sha256sum -c app-backup-update-VERSION.run.sha256
sudo bash app-backup-update-VERSION.run

VERSION durch den tatsächlichen Dateinamen ersetzen. Ein Git-Checkout auf dem Server ist nicht erforderlich. Der Installer benötigt die vorhandene Konfiguration /etc/app-backup/app-backup.conf und die bisherigen aktiven Zugangsdaten.

Der Start ist die Freigabe für das Update einschließlich eines vollständigen Backups mit zeitweiliger Unterbrechung der konfigurierten Anwendungen.

Was automatisch passiert

  1. Paketinhalt per SHA-256 prüfen und geschützt unter /var/tmp entpacken.
  2. Bestehende Einstellungen nach /var/backups/app-backup-upgrade-XXXXXXXX sichern.
  3. Aktuelle Pfade und Einstellungen übernehmen; sichere Betriebsoptionen ergänzen.
  4. Vorhandene Webdienste und direkt erkennbare Nextcloud-systemd-Writer zuordnen.
  5. Crypt-Konfiguration, DB-Dateien, globales DB-Recht RELOAD und bei MariaDB Zugriff auf Routinen-Metadaten prüfen; vorhandene Schlüssel/Passwörter erhalten. Keine automatischen DB-Grants.
  6. Vorprüfung mit geschützten Kopien durchführen. Bei Fehlern bleibt das installierte Paket samt Anwendungskonfiguration und Timer unverändert.
  7. Einen von SSH unabhängigen systemd-Auftrag app-backup-upgrade.service mit --no-block einreihen und die Sperren an ihn übergeben.
  8. Backup-Timer stoppen, Paket mit Rollback-Inventar installieren, Konfiguration atomar übernehmen und Rechte der aktiven root-eigenen Zugangsdaten korrigieren.
  9. Vollständiges Backup ohne lokale/Remote-Retention durchführen. Anschließend den abgeschlossenen Satz nochmals über Crypt herunterladen und mit dem Restore prüfen.
  10. Erst bei Erfolg den Backup-Timer aktivieren und das Ergebnis protokollieren.

Es findet kein Import in produktive Anwendungen oder Datenbanken statt. Der Remote-Prüflauf belegt Archivlesbarkeit, ersetzt aber keinen fachlichen Test-Restore.

Verlauf und Ergebnis

sudo journalctl -fu app-backup-upgrade.service --no-pager

Der Starter nennt außerdem den konkreten Ergebnisordner:

sudo cat /var/backups/app-backup-upgrade-XXXXXXXX/result.txt
sudo less /var/backups/app-backup-upgrade-XXXXXXXX/update.log

Erwartet wird SUCCESS. Bei QUEUED oder RUNNING nicht parallel erneut starten. QUEUED bedeutet, dass der Auftrag zur Übergabe vorbereitet wurde und noch kein Worker den Start bestätigt hat. Ein erfolgreicher Starter bestätigt nur die Annahme durch systemd; Installation und Backup können anschließend noch scheitern. Nach Ende verschwindet die kurzlebige systemd-Unit durch --collect auch bei Fehlern. Unit ... could not be found ist daher kein Erfolgsnachweis und verhindert die Journalabfrage nicht. Log und Ergebnis bleiben erhalten. Diagnose ohne Pager:

sudo journalctl -u app-backup-upgrade.service -n 100 --no-pager -l
sudo systemctl status app-backup-upgrade.service --no-pager -l

Bleibt QUEUED stehen, zuerst das Journal prüfen: Ein Fehler noch vor dem Start des Bash-Workers (z. B. ein nicht ausführbarer Paketpfad) kann noch nicht in update.log oder result.txt durch den Worker protokolliert werden. Ein späterer Sperr-Timeout erscheint dagegen in beiden Dateien. Nicht allein auf den Exit-Code von systemd-run vertrauen. --foreground führt den Vorgang stattdessen im aktuellen Terminal aus und ist für Tests/Diagnose gedacht; dabei besteht keine Absicherung gegen SSH-Abbruch.

Gezielte Rückfragen und Grenzen

  • Zentrales Mailverzeichnis fehlt, etwa /var/vmail: Der Installer fragt vor der Installation nach dem tatsächlichen absoluten Pfad. Alternativ lässt sich dieser mit --mail-dir /tatsaechliche/mailablage übergeben. Kein leeres Ersatzverzeichnis anlegen: Das würde fehlende Maildaten nur verdecken. Liegen alle Mailboxen in den angezeigten MAIL_HOME_DIRS, im Dialog homes wählen und die vollständige Abdeckung bestätigen. --mail-homes-only erteilt dieselbe ausdrückliche Bestätigung ohne Dialog. Dabei müssen die Home-Sicherung aktiviert und alle konfigurierten Homes vorhanden sein. Excludes und Dateisystemgrenzen gelten weiterhin; ausgeschlossene Verzeichnisse, verlinkte externe Mailablagen und weitere Mounts sind dadurch nicht abgedeckt. Postfix/Dovecot-Konfigurationen und Maildienst-Stopps bleiben aktiv. Bei unbekannter Mailablage abbrechen und zuerst die Mailserver-Konfiguration prüfen. Ein fehlender Pfad wird nie automatisch übersprungen.
  • Rclone-Datei nicht eindeutig: Pfad im Dialog oder mit --rclone-config FILE angeben. Eine user-eigene Datei wird in eine neue root-eigene Datei kopiert; die vom Benutzer verwendete Originaldatei bleibt unverändert.
  • Gitea bisher nicht konfiguriert: Aufnahme bestätigen oder bewusst --no-gitea setzen. Absolute explizite Pfade und der MySQL-DB-Name können aus app.ini übernommen werden. Mehrdeutige/relative Pfade müssen zuerst in der vorhandenen Backup-Konfiguration ergänzt werden; es werden keine geratenen Repository-Pfade eingetragen.
  • Nextcloud in crontab: Der Installer fragt, ob der gefundene Cron-Dienst während jeder Sicherung angehalten werden darf. Das betrifft auch andere Cronjobs; währenddessen fällige Jobs können ausfallen. Alternativ Nextcloud zuvor in einen eigenen systemd-Service/Timer übertragen. Bereits gestartete direkte cron.php-/occ-Prozesse werden nach dem Writer-Stopp abgewartet (Default 300 Sekunden), nicht blind beendet. Shell-Wrapper, externe Scheduler und nicht direkt erkennbare Writer müssen explizit berücksichtigt werden.
  • Fehlende Basispakete: Installation über dnf nach Rückfrage oder mit --install-deps. Keine automatische Aktualisierung von PHP, DB-Server oder rclone auf eine möglicherweise inkompatible Version.
  • Verschlüsselte rclone-Konfigurationsdatei: Die für rclone benötigte Entsperrung muss auch im systemd-Kontext verfügbar sein. Ohne verfügbare Entsperrung bricht die Prüfung ab, statt unsichtbar auf eine Passworteingabe zu warten. Der Installer legt keine neuen Crypt-Passwörter an und exportiert keine fremden Secret-Stores.
  • Früher eingecheckte DB-Passwörter: Passwortrotation bleibt separat, weil weitere Benutzer derselben Accounts nicht zuverlässig ermittelt werden können.

Optionen können kombiniert werden:

sudo bash app-backup-update-VERSION.run \
  --rclone-config /root/.config/rclone/rclone.conf \
  --enable-gitea --cron-services nextcloudcron.timer,nextcloudcron.service

Die Remote-Retention bleibt nach der Migration ausgeschaltet. Nach einem echten Test-Restore bei Bedarf bewusst wieder aktivieren. Bestehende Timer-Zeitpläne bleiben erhalten; beim Aktivieren kann Persistent=true einen Lauf nachholen.

Fehler und Rückweg

Startfehler nach genau 60 Sekunden bei älteren Paketen

Die Pakete 8e6c9a058fa9 und 56fbcdad74f4 enthielten einen Fehler in der systemd-Übergabe: Der Starter hielt die Update-Sperre und wartete synchron auf den Abschluss des Startauftrags einer Type=oneshot-Unit. Dieser Startauftrag endet erst mit dem Worker; der Worker wartete aber selbst auf die Sperre des Starters. Nach 60 Sekunden brach seine Sperranforderung ab, noch vor Installation und Timer-Stopp. In diesem Ablauf ist kein Rollback erforderlich. Der ursprüngliche Worker hatte vor dem Sperrwarten noch kein eigenes Log eingerichtet, daher konnte die Fehlermeldung auf den systemd-Exit-Code beschränkt bleiben.

Das korrigierte Paket verwendet systemd-run --no-block und gibt zuerst die Backup-Sperre, dann die Update-Sperre frei. Eine fehlgeschlagene Übergabe entzieht auch einem möglicherweise schon eingereihten Worker die Freigabe. Die Sperren bleiben als Schutz vor parallelen Backups/Updates erhalten. Erneut das neue Paket starten; weder Sperrdateien löschen noch alte Worker manuell nachstarten.

Das Verhalten von --no-block und --collect ist in der systemd-Dokumentation beschrieben, der Startabschluss von oneshot in systemd.service.

Fehlende Mailablage und erneuter Start

Ein Abbruch Missing source: /var/vmail bei der Vorprüfung, wie beim Paket 8e6c9a058fa9, erfordert kein Rollback. Mit dem korrigierten Paket erneut starten und die Mailablage klären. Die bisherige Konfiguration und der Timer sind erhalten; der abgebrochene Versuch enthält noch kein erfolgreiches neues Backup. Bereits bewusst getroffene Entscheidungen können als Optionen mitgegeben werden:

sudo bash app-backup-update-VERSION.run --enable-gitea --cron-services crond.service

Diese Optionen passen nur, wenn Gitea aufgenommen werden soll und das Pausieren aller Cronjobs über crond.service ausdrücklich akzeptiert wurde.

Für Mailablagen wie /home/johannes/Mail unter den konfigurierten Benutzerhomes zusätzlich --mail-homes-only verwenden, sofern damit alle Postfächer erfasst sind:

sudo bash app-backup-update-VERSION.run \
  --enable-gitea --cron-services crond.service --mail-homes-only

Der Installer zeigt die übernommenen Home-Verzeichnisse an. Mail/ einschließlich cur, new, tmp und Dovecot-Dateien wird mit den normalen Home-Excludes der Vorlage vollständig kopiert, sofern es auf demselben Dateisystem liegt und kein Verweis auf eine externe Ablage ist. Weitere Benutzer müssen in MAIL_HOME_DIRS stehen; das Vorhandensein eines einzelnen Postfachs belegt nicht deren Abdeckung.

Fehler nach Installationsbeginn

Bei einem Fehler nach Beginn der Installation bleibt der Backup-Timer gestoppt. Es erfolgt kein automatisches Zurücksetzen über möglicherweise noch laufende oder teilweise wiederhergestellte Anwendungen. Logs und gegebenenfalls recovery-*.json im Workdir prüfen. Das kombinierte Rollback stellt die vorherigen Paketdateien und die vorherige Backup-Hauptkonfiguration wieder her:

sudo bash /var/backups/app-backup-upgrade-XXXXXXXX/rollback-update.sh

Es verändert keine gesicherten Anwendungsdaten, rotiert keine Zugangsdaten und startet den Timer nicht ungeprüft. Neu erzeugte root-eigene Kopien von rclone-Dateien sowie strengere Dateirechte bleiben erhalten. Bei unterbrochener Vorbereitung ohne Installationsbeginn ist kein Paket-Rollback erforderlich.

Fehlendes DB-Recht RELOAD

mariadb-dump: ... FLUSH ... Access denied ... RELOAD ... (1227) bedeutet: Die Anmeldung funktioniert, aber dem tatsächlich verwendeten DB-Konto fehlt das globale Sperrrecht für --lock-all-tables. Ein pauschaler Wechsel auf einen Dump ohne Sperren oder ausschließlich --single-transaction ist bei gemischten Storage Engines kein gleichwertiger Ersatz. Das neue Paket prüft RELOAD bereits vor Installation und Wartungsmodus über lesende Privileg-Metadaten.

Die tatsächlich authentifizierten Konten und Serverversionen ermitteln. Zunächst eine Root-Shell starten:

sudo bash

Erst in dieser Shell den folgenden Block ausführen. Er gibt keine Passwörter oder Authentifizierungshashes aus und beendet anschließend die Root-Shell:

source /etc/app-backup/app-backup.conf
query='SELECT CURRENT_USER(), VERSION()'
echo WordPress
mariadb --defaults-extra-file="$WP_DB_CNF" -N -B -e "$query"
echo Nextcloud
mariadb --defaults-extra-file="$NC_DB_CNF" -N -B -e "$query"
echo Gitea
mariadb --defaults-extra-file="$GITEA_DB_CNF" -N -B -e "$query"
exit

Nur die Zeilen für tatsächlich konfigurierte Anwendungen ausführen. Die getrennte Root-Shell vermeidet Probleme durch kopierte Einrückungen an Here-Doc-Abschlussmarken.

Mit einem DB-Administratorkonto nur die betroffenen, vorhandenen Backup-Konten berechtigen. Beispiel für das zuvor tatsächlich identifizierte Konto backup@localhost (nicht ungeprüft übernehmen):

GRANT RELOAD ON *.* TO 'backup'@'localhost';

RELOAD ist ein globales Verwaltungsrecht zum Flush/Reload; deshalb wird es nicht automatisch durch den Paketinstaller vergeben. Keine pauschalen ALL PRIVILEGES oder GRANT OPTION erteilen. Wenn die CNF ein produktives Anwendungskonto verwendet, ein separates Backup-Konto mit gezielten Rechten vorbereiten. Ein zusätzliches FLUSH PRIVILEGES ist nach GRANT nicht notwendig. Quelle: MariaDB GRANT.

Für MariaDB prüft das Paket außerdem den Lesezugriff auf mysql.proc, den die verwendete Option --routines benötigt. Falls dieser fehlt, gezielt für das identifizierte Backup-Konto vergeben:

GRANT SELECT ON mysql.proc TO 'backup'@'localhost';

Auch dies ist ein Beispiel mit zu ersetzendem Kontonamen. Es erlaubt den Zugriff auf Routinen-Metadaten datenbankübergreifend; kein SELECT ON mysql.* vergeben. Quelle: MariaDB mariadb-dump / routines.

Weitere erforderliche Rechte hängen von Views, Triggern und Events ab; RELOAD allein ersetzt keine Leserechte auf den zu sichernden Datenbanken. Die neue Prüfung deckt die globale Sperrberechtigung und MariaDB-Routinen-Metadaten ab, nicht sämtliche möglichen Objektrechte. Der vollständige Abnahmelauf bleibt verpflichtend.

Beim gemeldeten Lauf vom 10.09.2026 um 14:41 Uhr war das Paket bereits installiert, als der erste Dump scheiterte. Nextcloud verließ laut Log den Wartungsmodus und Cron wurde wieder gestartet. Das ist kein erfolgreiches Backup; der Timer bleibt bis zur Abnahme gestoppt. Nach Rechtekorrektur das aktuelle Paket erneut starten: Es prüft, sichert und aktiviert den Timer erst nach erfolgreicher Remote-Prüfung. Ein erneuter Paketlauf erhält die ursprüngliche Sicherung des vorigen Update-Versuchs. Für einen Rückweg zum Stand vor dem ersten Installationslauf ist dessen Rollback-Ordner maßgeblich; ein späterer Snapshot enthält bereits die zuvor installierte Version.

Dienst-Stopps/-Starts und das Warten auf Nextcloud-Writer werden jetzt ausdrücklich im Journal protokolliert. Eine längere Pause ohne CPU-Last lässt sich so einem konkreten Dienst zuordnen; ohne dessen Journal lässt sich die Ursache der Pause nicht aus ihrer Dauer allein bestimmen.

Paket reproduzieren

Aus einem sauberen, eingecheckten Repository:

python3 tools/build-update-package.py

Ausgabe: dist/app-backup-update-COMMIT.run und zugehörige SHA-256-Datei. Das Paket enthält nur explizit freigegebene Programm-/Dokumentationsdateien und Credential-Vorlagen; keine Git-Historie, echten CNF-Dateien oder Backupdaten. Die Prüfsumme schützt vor Übertragungsfehlern, ist keine digitale Signatur. Das ausführbare Paket ausschließlich über euren vertrauenswürdigen Kanal beziehen.

Verifikation der Lieferung

41 Container-Tests sowie ShellCheck und Shell-Syntaxprüfung erfolgreich. Die Tests enthalten echte MariaDB-Dumps/Imports und lokale rclone-Crypt-Roundtrips; systemd/occ und die systemd-run-Übergabe sind simuliert. Das Übergabemodell berücksichtigt jetzt das Warten auf den oneshot-Startauftrag: Der Regressionstest scheiterte mit dem alten Code und war nach dem Fix erfolgreich. Geprüft sind auch abgewiesene Übergaben, eingereihte Worker trotz fehlgeschlagener Antwort und persistente Fehlerprotokolle bei belegter Update-Sperre. Die tatsächliche Server-/OneDrive-Prüfung erfolgt beim ersten Paketlauf. Ein fachlicher Restore auf einem separaten Testsystem bleibt erforderlich.