diff --git a/README.md b/README.md index c9dba24..ec2aa20 100644 --- a/README.md +++ b/README.md @@ -1,113 +1,340 @@ -# app-backup (Rocky Linux / Apache / Postfix) +# app-backup (Rocky Linux 10) – Split-Backups für WordPress, Nextcloud, Gitea + DBs (OneDrive/rclone) -Resiliente tägliche Backups für **WordPress**, **Nextcloud** und **Mail** (Postfix/Dovecot optional). -Erzeugt **timestamped Archive**, lädt nach **OneDrive** via **rclone** und verschickt einen **Mail-Report** an den lokalen User **johannes**. +Dieses Repo enthält ein **Backup- und Restore-Setup** für typische Self-Hosted-Apps auf Rocky Linux 10: -Enthält zusätzlich ein Restore-Script mit **Dry-Run**, **Service-Stop/Start** und **Nextcloud Maintenance Mode**. +- **WordPress** (Webroot) +- **Nextcloud** (Code + Data getrennt; Data liegt bei uns unter `.../nextcloud/data`) +- **Gitea** (native Installation via systemd + MariaDB) +- **MariaDB-Dumps** (WordPress DB, Nextcloud DB, Gitea DB) +- Upload nach **OneDrive** per **rclone** -## Installation +Neu in dieser Version: **kein riesiges “Alles-in-eins”-Archiv** mehr, sondern **sauber getrennte Archives pro Komponente**. Das macht Uploads stabiler (große Dateien), Restore selektiver und Fehler leichter eingrenzbar. -Pakete: -```bash -sudo dnf install -y rsync tar zstd gzip rclone mariadb postfix +--- + +## ✅ Ziele / Designentscheidungen + +### 1) Split statt „dickes Archiv“ +Es werden pro Lauf mehrere Archive erzeugt (zstd oder gzip): + +- `..._meta.tar.zst` – Meta (Timestamp, Hostname, Größeninfos) +- `..._db.tar.zst` – DB Dumps (SQL Dateien) +- `..._wordpress.tar.zst` – WordPress Webdaten (ohne Nextcloud-Unterordner) +- `..._nextcloud.tar.zst` – Nextcloud **Code/Web** (mit Exclude `data/`) +- `..._nextcloud-data.tar.zst` – Nextcloud **Data** separat +- `..._gitea.tar.zst` – Gitea Data (APP_DATA_PATH) +- `..._gitea-etc.tar.zst` – `/etc/gitea` (Gitea config) + +Vorteile: +- Upload stabiler bei **12–18 GB** (nicht 1 Monolith) +- Restore selektiv (z.B. nur DB, nur Nextcloud-data, …) +- Fehlerbehebung leichter (ein Archiv kaputt → nicht alles kaputt) + +### 2) Nextcloud data unterhalb von `NC_DIR` +Bei uns liegt Nextcloud so: + +- `NC_DIR=/var/www/html/nextcloud` (Code) +- `NC_DATA_DIR=/var/www/html/nextcloud/data` (Data) + +Damit **Data nicht doppelt** gesichert wird: +- Beim Backup von `NC_DIR` wird `data/` **explizit ausgeschlossen** (`rsync --exclude data/`). +- Danach wird `NC_DATA_DIR` als eigenes Paket gesichert. + +### 3) WordPress liegt im Webroot `/var/www/html` und Nextcloud als Unterordner +Bei uns liegt: +- WordPress im `WP_DIR=/var/www/html` +- Nextcloud in `/var/www/html/nextcloud` + +Damit Nextcloud nicht im WP-Archiv landet: +- WP-Backup schließt `nextcloud/` automatisch aus, wenn `NC_DIR` genau `WP_DIR/nextcloud` ist. + +### 4) rclone / OneDrive robust für große Dateien +Upload wird robust gemacht mit: +- Chunking: `--onedrive-chunk-size 64M` +- Timeouts: `--timeout 1h`, `--contimeout 30s` +- konservativ: `--transfers 2`, `--checkers 4` +- mehr Retries: `--retries 10`, `--low-level-retries 40` + +Außerdem: **Remote-Namen sind case-sensitive!** +Remote ist bei uns z.B. `OneDrive:` (nicht `onedrive:`). + +--- + +## 📦 Dateien & Pfade + +### Skripte +- `app-backup.sh` → Backup erstellen, Archive erzeugen, optional Upload. +- `app-restore.sh` → Restore aus lokalem Ordner oder OneDrive-Run-Folder. +- `app-backup.conf` → Konfiguration (Pfad/Services/DB/Credentials). + +### Zielpfade (Standard) +- Workdir: `/var/backups/app-backup` +- Archive: `/var/backups/app-backup/archives` +- Logs: `/var/log/app-backup` + +### OneDrive Ziel (Beispiel) +Upload in: +``` +OneDrive:Sicherung/JRITServerBackups//appbackup_/ ``` -Repo deploy: +--- + +## 🔧 Installation / Setup + +### 1) Skripte installieren +Beispiel: ```bash -./install.sh +sudo install -d /etc/app-backup /usr/local/sbin +sudo install -m 0755 app-backup.sh /usr/local/sbin/app-backup.sh +sudo install -m 0755 app-restore.sh /usr/local/sbin/app-restore.sh +sudo install -m 0640 app-backup.conf /etc/app-backup/app-backup.conf ``` -## Konfiguration +### 2) DB Credential Files anlegen +Für WordPress / Nextcloud / Gitea je eine `.cnf`. -Konfig anpassen: -- `/etc/app-backup/app-backup.conf` +Beispiele: +- `/etc/app-backup/db-wordpress.cnf` +- `/etc/app-backup/db-nextcloud.cnf` +- `/etc/app-backup/db-gitea.cnf` -DB-Credentials (aus Templates): +Inhalt: +```ini +[client] +user=backup +password=DEIN_PASSWORT +host=localhost +``` + +Rechte: ```bash -sudo cp /etc/app-backup/db-wordpress.cnf.example /etc/app-backup/db-wordpress.cnf -sudo cp /etc/app-backup/db-nextcloud.cnf.example /etc/app-backup/db-nextcloud.cnf -sudo chmod 600 /etc/app-backup/db-*.cnf sudo chown root:root /etc/app-backup/db-*.cnf +sudo chmod 600 /etc/app-backup/db-*.cnf ``` -rclone für root testen: +### 3) MariaDB Backup-User (Minimal-Rechte) +Pro DB (z.B. gitea): +```sql +CREATE USER 'backup'@'localhost' IDENTIFIED BY 'DEIN_PASSWORT'; +GRANT SELECT, SHOW VIEW, TRIGGER, EVENT, LOCK TABLES ON gitea.* TO 'backup'@'localhost'; +FLUSH PRIVILEGES; +``` + +Optional: denselben User für wordpress/nextcloud verwenden, dann jeweils `GRANT ... ON wordpress.*` etc. + +### 4) rclone Remote prüfen (Case-Sensitive!) +Auf dem Server (als derselbe User, der später rclone nutzt – typischerweise root oder johannes): +```bash +rclone listremotes +rclone lsf "OneDrive:" --max-depth 1 +rclone lsf "OneDrive:Sicherung" --max-depth 1 +``` + +⚠️ Wichtig: Wenn das Backup als `root` läuft, muss `root` auch Zugriff auf die rclone config haben. +Typisch sind zwei Wege: + +**Option A – root nutzt eigene rclone config** +- `sudo rclone config` als root durchführen und Remote anlegen. + +**Option B – root nutzt Config von johannes** +- im Script/Service `RCLONE_CONFIG=/home/johannes/.config/rclone/rclone.conf` setzen +- oder in systemd Unit `Environment=RCLONE_CONFIG=...` + +--- + +## ⚙️ Konfiguration: app-backup.conf (wichtige Stellen) + +### OneDrive Remote Base +```bash +RCLONE_REMOTE_BASE="OneDrive:Sicherung/JRITServerBackups/$(hostname -s)" +``` + +Das Skript legt pro Run einen Unterordner an: +```bash +remote_run="${RCLONE_REMOTE_BASE}/appbackup_" +``` + +### WordPress / Nextcloud Layout (wichtig!) +```bash +WP_DIR="/var/www/html" +NC_DIR="/var/www/html/nextcloud" +NC_DATA_DIR="/var/www/html/nextcloud/data" +``` + +Damit wird: +- WordPress = alles in `/var/www/html` **ohne** `nextcloud/` +- Nextcloud Code = `/var/www/html/nextcloud` **ohne** `data/` +- Nextcloud Data = `/var/www/html/nextcloud/data` separat + +### Gitea (native + MariaDB) +Aus deinem systemd/app.ini: +- `WorkingDirectory=/var/lib/gitea` +- `APP_DATA_PATH=/var/lib/gitea/data` +- config: `/etc/gitea/app.ini` + +Daher: +```bash +ENABLE_GITEA="true" +GITEA_SERVICE_NAME="gitea" +ENABLE_GITEA_SERVICE_STOP="true" + +GITEA_DATA_DIR="/var/lib/gitea/data" +GITEA_ETC_DIR="/etc/gitea" + +GITEA_DB_NAME="gitea" +GITEA_DB_CNF="/etc/app-backup/db-gitea.cnf" +``` + +--- + +## ▶️ Backup ausführen + +```bash +sudo /usr/local/sbin/app-backup.sh +``` + +Erwartetes Verhalten: +1) Lock `/run/app-backup.lock` verhindert Parallelruns +2) optional stoppt es Gitea kurz (konsistenter Snapshot) +3) Dumps: wordpress / nextcloud / gitea +4) rsync in staging +5) mehrere `.tar.zst` werden erzeugt +6) Upload pro Datei nach OneDrive (falls `ENABLE_UPLOAD=true`) +7) Remote retention (best effort) +8) lokale Retention löscht alte Archive + +--- + +## ♻️ Restore ausführen + +### Restore von OneDrive (Run-Ordnername angeben) +Du brauchst den Ordnernamen, z.B.: +`appbackup_2026-02-11_02-31-28` + +Dann: +```bash +sudo /usr/local/sbin/app-restore.sh --remote-run appbackup_2026-02-11_02-31-28 +``` + +### Restore aus lokalem Ordner +Wenn du die Archive lokal hast: +```bash +sudo /usr/local/sbin/app-restore.sh --local-run /var/backups/app-backup/archives/ +``` + +### Dry-Run +```bash +sudo /usr/local/sbin/app-restore.sh --remote-run appbackup_... --dry-run +``` + +### Nur Files / nur DB +```bash +sudo /usr/local/sbin/app-restore.sh --remote-run appbackup_... --no-db +sudo /usr/local/sbin/app-restore.sh --remote-run appbackup_... --no-files +``` + +--- + +## 🧠 Restore-Details (was passiert danach?) + +### Nextcloud +- Maintenance Mode wird optional aktiviert (konfigurierbar) +- Restore kopiert Code und Data getrennt zurück +- Danach: + - `occ maintenance:repair` + - optional `occ files:scan --all` (deaktiviert per default; kann lange dauern) + +### Gitea +- Service wird optional gestoppt +- Data wird nach `GITEA_DATA_DIR` zurück synchronisiert +- `/etc/gitea` wird wiederhergestellt +- DB Dump wird importiert +- Service wird wieder gestartet + +--- + +## 🧯 Troubleshooting + +### 1) rclone Remote not reachable / “didn't find section in config file” +Typischer Fehler: +- Remote heißt `OneDrive:` aber Config nutzt `onedrive:` → **case-sensitive**. +- Backup läuft als `root`, aber rclone config ist nur bei `johannes`. + +Prüfen: ```bash sudo rclone listremotes -sudo rclone lsd onedrive: +sudo -u johannes rclone listremotes ``` -## Backup Timer +Fix: +- Entweder rclone remote auch für root konfigurieren, +- oder `RCLONE_CONFIG` auf johannes’ Config zeigen lassen. -Timer aktivieren (macht install.sh bereits): +### 2) Nextcloud Data doppelt oder fehlt +Stellen prüfen: +- `NC_DIR` korrekt? +- `NC_DATA_DIR` korrekt? +- Das Skript excludet `data/` bei Nextcloud Code. Data wird separat gesichert. + +### 3) Große Uploads brechen ab +Setze z.B.: +- `RCLONE_TRANSFERS=1` +- `RCLONE_CHECKERS=2` +- `RCLONE_ONEDRIVE_CHUNK_SIZE=32M` +- optional `RCLONE_BWLIMIT="20M"` + +### 4) Restore soll “hart” spiegeln +Standard ist vorsichtig (kein delete). Wenn du wirklich Ziel-Verzeichnisse exakt spiegeln willst: ```bash +RESTORE_STRICT_DELETE="true" +``` +⚠️ Achtung: Das kann Dateien löschen, die nicht im Backup sind. + +--- + +## 🗓️ Optional: systemd Service + Timer (Beispiel) + +> Nur als Beispiel – wenn ihr mögt, legen wir das als Files ins Repo. + +`/etc/systemd/system/app-backup.service` +```ini +[Unit] +Description=app-backup +After=network.target mariadb.service +Wants=mariadb.service + +[Service] +Type=oneshot +ExecStart=/usr/local/sbin/app-backup.sh +``` + +`/etc/systemd/system/app-backup.timer` +```ini +[Unit] +Description=Run app-backup daily + +[Timer] +OnCalendar=daily +Persistent=true + +[Install] +WantedBy=timers.target +``` + +Aktivieren: +```bash +sudo systemctl daemon-reload sudo systemctl enable --now app-backup.timer -sudo systemctl list-timers | grep app-backup ``` -Manueller Testlauf: -```bash -sudo systemctl start app-backup.service -journalctl -u app-backup.service -n 200 --no-pager -ls -la /var/log/app-backup/ -ls -la /var/backups/app-backup/archives/ -``` +--- -## Disk-Schutz / Retention (wichtig) - -Um ein volllaufendes Dateisystem zu vermeiden, gilt: - -- **Lokale Archive werden maximal `LOCAL_RETENTION_DAYS` Tage aufbewahrt** (Standard: **7 Tage**) -- Zusätzlich wird vor und nach dem Staging geprüft, ob mindestens **`MIN_FREE_GB` GiB** frei sind (Standard: **10 GiB**). -- Gelöschte Backups werden im **Mail-Report** aufgeführt (Anzahl + grob freigegebener Speicher). - -Einstellungen in `/etc/app-backup/app-backup.conf`: -- `LOCAL_RETENTION_DAYS=7` -- `MIN_FREE_GB=10` - -## Mail-Report - -Versand per Postfix `/usr/sbin/sendmail` an `MAIL_TO` (Default: `johannes`). -Der Report enthält u.a.: -- Status (SUCCESS/FAIL), Laufzeit -- Was gesichert wurde + Größen -- Upload-Status (rclone) -- **Wie viele alte lokale Backups gelöscht wurden (Retention)** - -## Restore (Wiederherstellung) - -### Dry-Run (empfohlen) -```bash -sudo /usr/local/sbin/app-restore.sh --archive /var/backups/app-backup/archives/appbackup_YYYY-mm-dd_HH-MM-SS.tar.zst --dry-run -``` - -### Restore aus lokalem Archiv -```bash -sudo /usr/local/sbin/app-restore.sh --archive /var/backups/app-backup/archives/appbackup_YYYY-mm-dd_HH-MM-SS.tar.zst -``` - -### Restore direkt aus OneDrive (Download + Restore) -```bash -sudo /usr/local/sbin/app-restore.sh --remote-file appbackup_YYYY-mm-dd_HH-MM-SS.tar.zst -``` - -### Teil-Restore -Nur Nextcloud + DB: -```bash -sudo /usr/local/sbin/app-restore.sh --archive /path/to/archive.tar.zst --only nextcloud,nextcloud-data,db -``` - -Alles außer Mail: -```bash -sudo /usr/local/sbin/app-restore.sh --archive /path/to/archive.tar.zst --skip mail -``` - -### Nach dem Restore prüfen -```bash -systemctl status httpd postfix dovecot --no-pager -tail -n 200 /var/log/app-backup/app-restore_*.log -``` - -Optional (kann dauern): -```bash -sudo -u apache php /var/www/html/nextcloud/occ maintenance:repair -``` +## ✅ Empfehlung: Restore-Test +Backups sind erst dann gut, wenn Restore getestet ist: +- Test-VM / Test-Host +- DB importieren +- Archive entpacken / rsync zurückspielen +- Nextcloud startet, Login klappt, Files sichtbar +- WordPress Frontend/Backend ok +- Gitea WebUI ok, Repos vorhanden