Added updated README.md for the new code base.
This commit is contained in:
403
README.md
403
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).
|
Dieses Repo enthält ein **Backup- und Restore-Setup** für typische Self-Hosted-Apps auf Rocky Linux 10:
|
||||||
Erzeugt **timestamped Archive**, lädt nach **OneDrive** via **rclone** und verschickt einen **Mail-Report** an den lokalen User **johannes**.
|
|
||||||
|
|
||||||
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/<hostname>/appbackup_<timestamp>/
|
||||||
```
|
```
|
||||||
|
|
||||||
Repo deploy:
|
---
|
||||||
|
|
||||||
|
## 🔧 Installation / Setup
|
||||||
|
|
||||||
|
### 1) Skripte installieren
|
||||||
|
Beispiel:
|
||||||
```bash
|
```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:
|
Beispiele:
|
||||||
- `/etc/app-backup/app-backup.conf`
|
- `/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
|
```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 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_<timestamp>"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 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/<run-folder>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 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
|
```bash
|
||||||
sudo rclone listremotes
|
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
|
```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 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)
|
## ✅ Empfehlung: Restore-Test
|
||||||
|
Backups sind erst dann gut, wenn Restore getestet ist:
|
||||||
Um ein volllaufendes Dateisystem zu vermeiden, gilt:
|
- Test-VM / Test-Host
|
||||||
|
- DB importieren
|
||||||
- **Lokale Archive werden maximal `LOCAL_RETENTION_DAYS` Tage aufbewahrt** (Standard: **7 Tage**)
|
- Archive entpacken / rsync zurückspielen
|
||||||
- Zusätzlich wird vor und nach dem Staging geprüft, ob mindestens **`MIN_FREE_GB` GiB** frei sind (Standard: **10 GiB**).
|
- Nextcloud startet, Login klappt, Files sichtbar
|
||||||
- Gelöschte Backups werden im **Mail-Report** aufgeführt (Anzahl + grob freigegebener Speicher).
|
- WordPress Frontend/Backend ok
|
||||||
|
- Gitea WebUI ok, Repos vorhanden
|
||||||
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
|
|
||||||
```
|
|
||||||
|
|||||||
Reference in New Issue
Block a user