# app-backup (Rocky Linux 10) – Split-Backups für WordPress, Nextcloud, Gitea + DBs (OneDrive/rclone) Dieses Repo enthält ein **Backup- und Restore-Setup** für typische Self-Hosted-Apps auf Rocky Linux 10: - **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** 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. --- ## ✅ 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_/ ``` --- ## 🔧 Installation / Setup ### 1) Skripte installieren Beispiel: ```bash 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 ``` ### 2) DB Credential Files anlegen Für WordPress / Nextcloud / Gitea je eine `.cnf`. Beispiele: - `/etc/app-backup/db-wordpress.cnf` - `/etc/app-backup/db-nextcloud.cnf` - `/etc/app-backup/db-gitea.cnf` Inhalt: ```ini [client] user=backup password=DEIN_PASSWORT host=localhost ``` Rechte: ```bash sudo chown root:root /etc/app-backup/db-*.cnf sudo chmod 600 /etc/app-backup/db-*.cnf ``` ### 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 -u johannes rclone listremotes ``` Fix: - Entweder rclone remote auch für root konfigurieren, - oder `RCLONE_CONFIG` auf johannes’ Config zeigen lassen. ### 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 ``` --- ## ✅ 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