9.1 KiB
app-backup – geprüfte Sicherungen für den JR IT Server
Sichert WordPress, Nextcloud, native Gitea-Installationen mit MariaDB, Maildaten und zusätzliche Verzeichnisse. Jede Komponente erhält ein eigenes Archiv. Uploads gehen ausschließlich über ein rclone-Crypt-Remote; anschließend wird der gesamte Inhalt durch dieses Remote zurückgelesen und verglichen.
Die vollständige Analyse, Architektur, Konfiguration, Betriebsanleitung und verbleibenden Grenzen stehen in Dokumentation.md.
Automatisches Update-Paket (empfohlen)
Das neue Paket übernimmt Konfigurationsabgleich, Rechteprüfung, Installation,
vollständigen Backup-Probelauf und Remote-Restore-Prüfung. Du benötigst auf dem
Server keinen Git-Checkout. Übertrage die gelieferte .run-Datei und ihre Prüfsumme
per SCP und starte im Zielverzeichnis:
sha256sum -c app-backup-update-VERSION.run.sha256
sudo bash app-backup-update-VERSION.run
VERSION durch den tatsächlichen Dateinamen ersetzen. Der längere Lauf arbeitet anschließend als systemd-Auftrag unabhängig von der SSH-Verbindung. Bei unklaren Gitea-/Cron-/rclone-Einstellungen fragt der Starter gezielt nach. Die Bedienung und der kombinierte Rückweg stehen in UPDATE_ANLEITUNG.md.
Die folgende manuelle Anleitung bleibt als Alternative für individuelle Updates.
Wesentliche Änderungen
- Funktionierender Restore mit Prüflauf, Entpackmodus, Komponentenauswahl und ausdrücklichem
--apply --yes. - Fehler bei Dump, rsync, Kompression und Rückleseprüfung brechen den Lauf ab.
- Wartungsmodus und Dienststopps umfassen Datenbankdump und Dateikopie. Danach endet die Ausfallzeit; Kompression und Upload laufen aus dem Staging.
- Vollständige Sicherungssätze mit SHA-256-Manifest, Archivprüfung und zuletzt hochgeladenem
COMPLETE-Marker. - Retention löscht nur vollständige neue Sicherungssätze und behält mindestens
RETENTION_KEEP_LASTLäufe. Alte Sicherungen werden nicht automatisch gelöscht. - Private Arbeitsverzeichnisse, gemeinsame Sperre für Backup/Restore/Update und Wiederanlaufhinweise nach Abbrüchen.
- Installer erhält die Serverkonfiguration und den Zeitplan und erstellt ein Rollback-Paket.
Bestehende Installation aktualisieren
Vor dem ersten Lauf: Für ein konsistentes Backup werden nun standardmäßig httpd, php-fpm, postfix und dovecot während der Kopie angehalten, soweit die zugehörigen Anwendungen aktiviert sind und die Dienste laufen. Fehlende Einstellungen in alten Konfigurationen erhalten diese neuen Defaults. Zusätzliche Cronjobs/Worker müssen in QUIESCE_SERVICES erfasst oder extern angehalten werden. Zeitfenster und Datenumfang vorher prüfen.
Die bisherigen echten *.cnf-Dateien wurden aus dem aktuellen Repository entfernt. Vor git pull auch mögliche Zugangsdaten im Server-Checkout sichern. Historische Commits können die alten Werte weiterhin enthalten; betroffene Datenbankpasswörter wechseln. Die Dateien unter /etc/app-backup werden vom Installer nicht überschrieben.
# Auf dem Server, im vorhandenen Checkout:
cd /pfad/zum/app-backup
sudo systemctl stop app-backup.timer
systemctl is-active app-backup.service
# Falls aktiv: den laufenden Job zuerst regulär fertig werden lassen.
# Einmalige geschützte Sicherung, bevor git pull alte Dateien aus dem Checkout entfernt:
sudo install -d -m 700 /var/backups/app-backup-before-v2
sudo cp -a /etc/app-backup /var/backups/app-backup-before-v2/etc-app-backup
sudo cp -a etc/app-backup /var/backups/app-backup-before-v2/checkout-app-backup
git status --short
# Lokale Anpassungen vorher sichern/auflösen; keinen Reset erzwingen.
git pull --ff-only
sudo ./install.sh
Der Installer nennt anschließend einen Ordner wie /var/backups/app-backup-update-XXXXXXXX mit alten Paketdateien und rollback.sh. Weil der Timer zuvor gestoppt wurde, bleibt er beim Update gestoppt. Eine sonst aktive Timer-Instanz wird vom Installer nach erfolgreichem Update wieder aktiviert; deshalb ist der vorherige Stopp für die Migration wichtig.
# Neue Optionen mit der bestehenden Konfiguration abgleichen (Datei enthält keine DB-Passwörter):
sudo diff -u /etc/app-backup/app-backup.conf /etc/app-backup/app-backup.conf.dist
sudoedit /etc/app-backup/app-backup.conf
# Vorhandene Dateinamen aus WP_DB_CNF / NC_DB_CNF / GITEA_DB_CNF verwenden:
sudo chown root:root /etc/app-backup/*.cnf
sudo chmod 600 /etc/app-backup/*.cnf
sudo chmod 600 /etc/app-backup/app-backup.conf
# Den tatsächlich konfigurierten rclone-Dateipfad verwenden:
sudo chown root:root /root/.config/rclone/rclone.conf
sudo chmod 600 /root/.config/rclone/rclone.conf
sudo /usr/local/sbin/app-backup.sh --check
# Im vereinbarten Wartungsfenster den ersten vollständigen Lauf ausführen:
sudo systemctl start app-backup.service
sudo journalctl -u app-backup.service -n 100 --no-pager
sudo cat /var/backups/app-backup/last-backup.json
--check prüft Werkzeuge, Quellpfade, Dateirechte, DB-Verbindungen, Speicherreserve und Crypt-Zugriff. Es stoppt keine Anwendungen und führt weder Backup noch Upload aus. Es ersetzt keinen vollständigen Probelauf.
In der Konfiguration insbesondere ergänzen/prüfen:
RCLONE_CONFIG="/root/.config/rclone/rclone.conf"
RCLONE_REMOTE_BASE="OneDriveCrypt:gemini" # vorhandenes Crypt-Ziel beibehalten!
RETENTION_KEEP_LAST=3
ENABLE_REMOTE_RETENTION="false" # während der Migration zunächst aus
MAIL_BACKUP_MODE="stop"
# Tatsächliche Timer-/Service-Namen einsetzen; Timer vor seinem Service nennen:
QUIESCE_SERVICES=()
# Gitea war in der bisherigen mitgelieferten Konfiguration NICHT aktiviert:
# ENABLE_GITEA="true" nach Prüfung aller Gitea-Pfade und DB-Einstellungen setzen.
Den neuen Laufnamen aus Log oder last-backup.json übernehmen:
sudo /usr/local/sbin/app-restore.sh --remote-run appbackup_DATUM_UHRZEIT_ID --verify-only
sudo /usr/local/sbin/app-restore.sh --remote-run appbackup_DATUM_UHRZEIT_ID --extract-only
DATUM_UHRZEIT_ID ist ein Platzhalter, z. B. 2026-09-10_02-30-00_a1b2c3d4. Der Entpackmodus nennt seinen geschützten Ergebnisordner. Nach Prüfung der Dateien und einer erfolgreichen Wiederherstellungsprobe auf einem Testsystem den Zeitplan einschalten:
sudo systemctl enable --now app-backup.timer
systemctl list-timers app-backup.timer
Rückweg bei einem Paketproblem: Timer stoppen, aktiven Job fertig werden lassen und das vom Installer erzeugte Skript ausführen:
sudo /var/backups/app-backup-update-XXXXXXXX/rollback.sh
Das stellt die ersetzten Paketdateien wieder her. Konfigurationsänderungen und bereits zurückgeschriebene Anwendungsdaten werden dadurch nicht rückgängig gemacht. Der Timer bleibt bis zur manuellen Prüfung gestoppt. Der alte Stand enthält die im Review beschriebenen Mängel.
Neuinstallation
Benötigt Linux mit systemd, Bash ≥ 4.4, Python ≥ 3.9, GNU tar/coreutils, rsync mit ACL/xattr-Unterstützung, zstd bzw. gzip, sudo, PHP/occ, MariaDB-Clients und rclone. Details und Rechte siehe Dokumentation.
git clone https://gitea.jr-it-services.de/johannes/app-backup.git
cd app-backup
sudo ./install.sh
sudoedit /etc/app-backup/app-backup.conf
# DB-Dateien aus *.cnf.example erstellen; root:root und chmod 600 setzen.
# rclone Crypt als root konfigurieren, Schlüssel getrennt sicher verwahren.
sudo /usr/local/sbin/app-backup.sh --check
Der Installer aktiviert bei einer Neuinstallation den Timer standardmäßig erst auf ausdrückliche Anforderung. Nach Backup- und Restore-Probe: sudo systemctl enable --now app-backup.timer.
Backup und Restore
sudo /usr/local/sbin/app-backup.sh
# Standard ist ein geprüfter Plan, ohne Änderungen an den Anwendungen:
sudo /usr/local/sbin/app-restore.sh --local-run /var/backups/app-backup/archives/LAUFNAME
# Ausführung überschreibt ausgewählte Dateien und Datenbankobjekte:
sudo /usr/local/sbin/app-restore.sh --config /etc/app-backup/restore.conf \
--local-run /var/backups/app-backup/archives/LAUFNAME --apply --yes
# Nur WordPress-Dateien; Konfiguration definiert die Zielpfade:
sudo /usr/local/sbin/app-restore.sh --local-run /var/backups/app-backup/archives/LAUFNAME \
--components wordpress --no-db --apply --yes
# Alte Split-Archive ohne Manifest: nur kontrolliert entpacken, manuell prüfen/importieren:
sudo /usr/local/sbin/app-restore.sh --local-run /pfad/zu/einem/alten/lauf \
--legacy-unverified --extract-only
Ein echter Restore benötigt passende Zielverzeichnisse, Anwendungsstände und Datenbanken sowie einen DB-Account mit Wiederherstellungsrechten. --yes ist keine automatische Datenrettung bei Fehlern; bei einem Teilfehler bleiben angehaltene Dienste für die manuelle Prüfung stehen.
Tests
docker build -t app-backup-test -f tests/Dockerfile .
docker run --rm --network none -v "$PWD:/src:ro" app-backup-test
ShellCheck, echte MariaDB-Dumps/Imports, gzip/zstd, rsync, lokale Crypt-Uploads und Remote-Restore sowie Fehlerfälle laufen im Container. systemd und Nextcloud-occ sind simuliert. Eine echte Rocky-/Nextcloud-/Gitea-/OneDrive-Wiederherstellungsprobe bleibt Teil der Serverabnahme.