Linux-use: Unterschied zwischen den Versionen

Aus Store2 Wiki
Zur Navigation springen Zur Suche springen
Markierungen: Manuelle Zurücksetzung Zurückgesetzt Visuelle Bearbeitung
Markierungen: Manuelle Zurücksetzung Visuelle Bearbeitung
 
(3 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt)
Zeile 1.017: Zeile 1.017:
'''Archiviert:''' <code>/mnt/user-data/outputs/STORE2-Network-Architecture-v1.0.md</code>
'''Archiviert:''' <code>/mnt/user-data/outputs/STORE2-Network-Architecture-v1.0.md</code>


= NVMe-Backup System - Vollständige Dokumentation v2.0 =
= NVMe-Backup & Datenbank-Backup System - Vollständige Dokumentation v3.0 =


== System-Übersicht ==
== System-Übersicht ==
'''Server:''' STORE2 (Debian 13) '''Zweck:''' Tägliche vollständige OS-Level Disaster Recovery Backups '''Backup-Methode:''' rsync mit Hard Link Deduplication und --one-file-system '''Backup-Größe:''' ~130GB pro Generation (apparent), ~37GB real durch Hard Links '''Retention:''' 21 Tage (daily.0 bis daily.20) '''Zeitplan:''' Täglich um 03:05 Uhr (±5min Randomisierung)
'''Server:''' STORE2 (Debian 13)


== Hardware-Konfiguration ==
'''Backup-Strategien:'''
'''Quelle:''' NVMe System-Laufwerk (/) '''Ziel:''' /mnt/nvme_backup - 1TB HDD (/dev/sdar1, ext4, Label: NVME_BACKUP) '''Kapazität:''' 21 Backup-Generationen bei ~85% HDD-Auslastung (geschätzt 777GB)


== Hard Link Backup-Technologie ==
# '''OS-Level Backup:''' Vollständiges System-Backup via rsync + Hard Links
# '''Datenbank-Backup:''' Zwei-Schicht-Strategie für Calibre/CWA SQLite-Datenbanken


=== Funktionsweise der Deduplication ===
----
 
== Teil 1: NVMe-Backup System (OS-Level) ==
 
=== Grundlegende Eigenschaften ===
 
* '''Zweck:''' Tägliche vollständige OS-Level Disaster Recovery Backups
* '''Methode:''' rsync mit Hard Link Deduplication und <code>--one-file-system</code>
* '''Backup-Größe:''' ~130GB pro Generation (apparent), ~37GB real durch Hard Links
* '''Retention:''' 21 Tage (daily.0 bis daily.20)
* '''Zeitplan:''' Täglich um 03:05 Uhr (±5min Randomisierung)
 
=== Hardware-Konfiguration ===
 
* '''Quelle:''' NVMe System-Laufwerk (/)
* '''Ziel:''' <code>/mnt/nvme_backup</code> - 1TB HDD (/dev/sdar1, ext4, Label: NVME_BACKUP)
* '''Kapazität:''' 21 Backup-Generationen bei ~85% HDD-Auslastung (geschätzt 777GB)
 
=== Hard Link Backup-Technologie ===
 
==== Funktionsweise der Deduplication ====


# '''Erste Generation (daily.0):''' Vollständiges Backup (~130GB apparent)
# '''Erste Generation (daily.0):''' Vollständiges Backup (~130GB apparent)
Zeile 1.034: Zeile 1.054:
# '''Gemessene Effizienz:''' 98-99% aller Dateien sind Hard-Linked zwischen Generationen
# '''Gemessene Effizienz:''' 98-99% aller Dateien sind Hard-Linked zwischen Generationen


=== Realistische Speichernutzung ===
==== Realistische Speichernutzung ====
daily.0: 130G apparent / 7.4GB real (neueste Generation) daily.1: 126G apparent / 85.5GB real (1 Tag alt) daily.2: 126G apparent / 4.1GB real (2 Tage alt)
<code>daily.0: 130G apparent / 7.4GB real (neueste Generation)
daily.1: 126G apparent / 85.5GB real (1 Tag alt)
daily.2: 126G apparent / 4.1GB real (2 Tage alt)</code>
'''Durchschnitt:''' ~37GB real pro Generation


'''Durchschnitt:''' ~37GB real pro Generation '''21 Generationen:''' ~777GB total (statt 2.7TB bei Vollbackups)
'''21 Generationen:''' ~777GB total (statt 2.7TB bei Vollbackups)


=== Pseudo-Inkrementelles System ===
==== Pseudo-Inkrementelles System ====


* Jede Generation erscheint als vollständiges Filesystem (130GB)
* Jede Generation erscheint als vollständiges Filesystem (130GB)
Zeile 1.046: Zeile 1.069:
* Keine Abhängigkeiten zwischen Generationen (jede ist vollständig)
* Keine Abhängigkeiten zwischen Generationen (jede ist vollständig)


== KRITISCH: Verzeichnis-Timestamps verstehen ==
=== KRITISCH: Verzeichnis-Timestamps verstehen ===
'''WICHTIG:''' Die Timestamps der daily.* Verzeichnisse sind NICHT die Backup-Zeiten!
'''WICHTIG:''' Die Timestamps der <code>daily.*</code> Verzeichnisse sind NICHT die Backup-Zeiten!


'''Warum alle Verzeichnisse das gleiche Datum zeigen:'''
'''Warum alle Verzeichnisse das gleiche Datum zeigen:'''
Zeile 1.054: Zeile 1.077:
* Das Skript macht: <code>mv daily.0 daily.1</code>, <code>mv daily.1 daily.2</code>, etc.
* Das Skript macht: <code>mv daily.0 daily.1</code>, <code>mv daily.1 daily.2</code>, etc.
* Die Directory-Timestamps bleiben beim ersten Erstellen eingefroren
* Die Directory-Timestamps bleiben beim ersten Erstellen eingefroren
'''Beispiel:''' Alle daily.0 bis daily.20 zeigen "7. Sep 11:12" - das ist das Datum, als die Rotation erstmals durchlief oder die Verzeichnisse initial erstellt wurden.


'''Wo sind die ECHTEN Backup-Zeiten?'''
'''Wo sind die ECHTEN Backup-Zeiten?'''


# '''Log-Dateien:''' /mnt/nvme_backup/_logs/run-YYYY-MM-DD_HH-MM-SS.log
# '''Log-Dateien:''' <code>/mnt/nvme_backup/_logs/run-YYYY-MM-DD_HH-MM-SS.log</code>
# '''Datei-mtimes:''' Dateien INNERHALB der Backups haben korrekte mtimes
# '''Datei-mtimes:''' Dateien INNERHALB der Backups haben korrekte mtimes
# '''SystemD Journal:''' journalctl -u nvme-backup.service
# '''SystemD Journal:''' <code>journalctl -u nvme-backup.service</code>


'''Backup-Alter prüfen:'''
'''Backup-Alter prüfen:'''


* Logs anschauen: ls -lth /mnt/nvme_backup/_logs/ | head
bash
* Nicht die Verzeichnis-Timestamps verwenden!
<code>ls -lth /mnt/nvme_backup/_logs/ | head</code>


== Software-Komponenten ==
=== Software-Komponenten ===


=== SystemD Services ===
==== SystemD Services ====
'''Service:''' nvme-backup.service - OneShot-Service für Backup-Ausführung '''Timer:''' nvme-backup.timer - Tägliche Ausführung um 03:05 Uhr (±5min) '''Mail-Services:'''


* nvme-backup-mail@success.service - Erfolgs-Benachrichtigung
* '''Service:''' <code>nvme-backup.service</code> - OneShot-Service für Backup-Ausführung
* nvme-backup-mail@failure.service - Fehler-Alarm
* '''Timer:''' <code>nvme-backup.timer</code> - Tägliche Ausführung um 03:05 Uhr (±5min)
* '''Mail-Services:'''
** <code>nvme-backup-mail@success.service</code> - Erfolgs-Benachrichtigung
** <code>nvme-backup-mail@failure.service</code> - Fehler-Alarm


=== Scripts und Pfade ===
==== Scripts und Pfade ====
'''Backup-Script:''' /usr/local/sbin/nvme-backup (KEEP=21) '''Mail-Script:''' /usr/local/sbin/nvme-backup-mailer '''Log-Verzeichnis:''' /mnt/nvme_backup/_logs/ '''Backup-Verzeichnisse:''' /mnt/nvme_backup/daily.0 bis daily.20


== Backup-Ablauf im Detail ==
* '''Backup-Script:''' <code>/usr/local/sbin/nvme-backup</code> (KEEP=21)
* '''Mail-Script:''' <code>/usr/local/sbin/nvme-backup-mailer</code>
* '''Log-Verzeichnis:''' <code>/mnt/nvme_backup/_logs/</code>
* '''Backup-Verzeichnisse:''' <code>/mnt/nvme_backup/daily.0</code> bis <code>daily.20</code>


=== Phase 1: Rotation (1-15 Minuten) ===
=== Backup-Ablauf im Detail ===
 
==== Phase 1: Rotation (1-15 Minuten) ====
Das Skript rotiert die Verzeichnisse rückwärts:
Das Skript rotiert die Verzeichnisse rückwärts:


# Lösche daily.21 (falls vorhanden) - '''rm -rf dauert lange!'''
# Lösche <code>daily.21</code> (falls vorhanden) - <code>rm -rf</code> dauert lange!
# Verschiebe daily.20 → daily.21
# Verschiebe <code>daily.20</code> <code>daily.21</code>
# Verschiebe daily.19 → daily.20
# Verschiebe <code>daily.19</code> <code>daily.20</code>
# ... bis daily.0 → daily.1
# ... bis <code>daily.0</code> <code>daily.1</code>
# Erstelle leeres daily.0
# Erstelle leeres <code>daily.0</code>


'''WICHTIG:''' Das Löschen von daily.21 kann 5-15 Minuten dauern (~49GB Hard-Links). Der Prozess "rm" erscheint in top mit hoher CPU-Last - das ist NORMAL!
'''WICHTIG:''' Das Löschen von <code>daily.21</code> kann 5-15 Minuten dauern (~49GB Hard-Links). Der Prozess "rm" erscheint in <code>top</code> mit hoher CPU-Last - das ist NORMAL!


=== Phase 2: rsync (15-60 Minuten) ===
==== Phase 2: rsync (15-60 Minuten) ====
rsync kopiert von / nach daily.0 mit:
rsync kopiert von <code>/</code> nach <code>daily.0</code> mit:


* --link-dest=daily.1 (Hard Links für unveränderte Dateien)
* <code>--link-dest=daily.1</code> (Hard Links für unveränderte Dateien)
* --delete (entfernt gelöschte Dateien aus daily.0)
* <code>--delete</code> (entfernt gelöschte Dateien aus daily.0)
* --one-file-system (ignoriert /data, /data2)
* <code>--one-file-system</code> (ignoriert <code>/data</code>, <code>/data2</code>)
* Fortschritt: Im Log <code>/mnt/nvme_backup/_logs/run-*.log</code>


'''Fortschritt:''' Im Log /mnt/nvme_backup/_logs/run-*.log
==== Phase 3: Fertigstellung ====
 
=== Phase 3: Fertigstellung ===
Script loggt "Backup OK" und beendet sich mit Exit 0.
Script loggt "Backup OK" und beendet sich mit Exit 0.


== rsync-Parameter ==
=== rsync-Parameter ===
'''Vollständiger Befehl:''' rsync -aAXH --delete --numeric-ids --info=progress2 --one-file-system --link-dest=daily.1 / /mnt/nvme_backup/daily.0
'''Vollständiger Befehl:'''


bash
<code>rsync -aAXH --delete --numeric-ids --info=progress2 --one-file-system \
  --link-dest=daily.1 / /mnt/nvme_backup/daily.0</code>
'''Kritische Parameter:'''
'''Kritische Parameter:'''


* '''-a:''' Archive-Mode (rlptgoD) - Permissions, Timestamps, etc.
* <code>-a</code>: Archive-Mode (rlptgoD) - Permissions, Timestamps, etc.
* '''-A:''' ACLs preservieren
* <code>-A</code>: ACLs preservieren
* '''-X:''' Extended Attributes preservieren
* <code>-X</code>: Extended Attributes preservieren
* '''-H:''' Hard Links im Quell-System preservieren
* <code>-H</code>: Hard Links im Quell-System preservieren
* '''--delete:''' Gelöschte Dateien auch aus Backup entfernen
* <code>--delete</code>: Gelöschte Dateien auch aus Backup entfernen
* '''--numeric-ids:''' UIDs/GIDs als Zahlen (nicht Namen)
* <code>--numeric-ids</code>: UIDs/GIDs als Zahlen (nicht Namen)
* '''--one-file-system:''' KRITISCH! Verhindert Backup der RAID-Mounts
* <code>--one-file-system</code>: '''KRITISCH!''' Verhindert Backup der RAID-Mounts
* '''--link-dest:''' Hard Links zu daily.1 für unveränderte Dateien
* <code>--link-dest</code>: Hard Links zu daily.1 für unveränderte Dateien


== Exclude-Liste ==
=== Exclude-Liste ===
Das Skript schließt folgende Pfade aus:
Das Skript schließt folgende Pfade aus:


/proc/ - Kernel-Prozess-Dateisystem /sys/ - Kernel-System-Dateisystem /dev/ - Device-Dateien /run/ - Runtime-Daten /tmp/ - Temporäre Dateien /data/ - RAID-Mount md125 (XFS, 52TB) /data2/ - RAID-Mount md126 (EXT4, 61TB) /lost+found - Dateisystem-Recovery /mnt/nvme_backup/* - Backup-Ziel selbst
* <code>/proc/</code> - Kernel-Prozess-Dateisystem
* <code>/sys/</code> - Kernel-System-Dateisystem
* <code>/dev/</code> - Device-Dateien
* <code>/run/</code> - Runtime-Daten
* <code>/tmp/</code> - Temporäre Dateien
* <code>/data/</code> - RAID-Mount md125 (XFS, 52TB)
* <code>/data2/</code> - RAID-Mount md126 (EXT4, 61TB)
* <code>/lost+found</code> - Dateisystem-Recovery
* <code>/mnt/nvme_backup/*</code> - Backup-Ziel selbst


== Backup-Inhalt ==
=== Backup-Inhalt ===
'''Vollständig gesichert:'''
'''Vollständig gesichert:'''


* /usr (21GB) - System-Binaries
* <code>/usr</code> (21GB) - System-Binaries
* /etc (399MB) - Konfigurationen
* <code>/etc</code> (399MB) - Konfigurationen
* /boot (417MB) - Kernel, Bootloader
* <code>/boot</code> (417MB) - Kernel, Bootloader
* /var (42GB) - Docker-Container, Emby-Metadaten, Systemlogs
* <code>/var</code> (42GB) - Docker-Container, Emby-Metadaten, Systemlogs
* /home (10.5GB) - User-Daten
* <code>/home</code> (10.5GB) - User-Daten
* /srv (9.5GB) - Service-Daten (Docker-Compose-Projekte)
* <code>/srv</code> (9.5GB) - Service-Daten (Docker-Compose-Projekte)
* /opt (1.5GB) - Zusatz-Software
* <code>/opt</code> (1.5GB) - Zusatz-Software
* /root (20GB) - Admin-Scripts und Configs
* <code>/root</code> (20GB) - Admin-Scripts und Configs


== KRITISCH: rsync Exitcode 24 ==
=== KRITISCH: rsync Exitcode 24 ===
'''Problem:''' rsync gibt Exitcode 24 zurück, wenn Dateien während des Backups verschwinden.
'''Problem:''' rsync gibt Exitcode 24 zurück, wenn Dateien während des Backups verschwinden.


Zeile 1.149: Zeile 1.186:
'''Tolerierte Exit-Codes:'''
'''Tolerierte Exit-Codes:'''


* 0: Perfekter Durchlauf
* <code>0</code>: Perfekter Durchlauf
* 23: Partial transfer (z.B. Permission-Probleme bei einzelnen Dateien)
* <code>23</code>: Partial transfer (z.B. Permission-Probleme bei einzelnen Dateien)
* 24: Some files vanished (normale Live-System-Situation)
* <code>24</code>: Some files vanished (normale Live-System-Situation)


== Mail-Benachrichtigungen ==
=== Mail-Benachrichtigungen ===


=== SMTP-Konfiguration ===
==== SMTP-Konfiguration ====
'''Provider:''' GMX (mail.gmx.net:587, TLS) '''Absender:''' dergagi@gmx.de '''Empfänger:''' daniel.gareis@gmail.com '''Auth:''' /etc/msmtprc (chmod 600)


=== Mail-Inhalt bei Erfolg ===
* '''Provider:''' GMX (mail.gmx.net:587, TLS)
* '''Absender:''' dergagi@gmx.de
* '''Empfänger:''' daniel.gareis@gmail.com
* '''Auth:''' <code>/etc/msmtprc</code> (chmod 600)
 
==== Mail-Inhalt bei Erfolg ====


* Backup-Statistiken (apparent/real size, übertragene Datenmenge)
* Backup-Statistiken (apparent/real size, übertragene Datenmenge)
Zeile 1.166: Zeile 1.207:
* Performance-Daten (Log-Größe, Dauer)
* Performance-Daten (Log-Größe, Dauer)


=== Mail-Inhalt bei Fehler ===
==== Mail-Inhalt bei Fehler ====


* Error-Details aus journalctl
* Error-Details aus journalctl
Zeile 1.173: Zeile 1.214:
* RAID-Status
* RAID-Status


== Wartung und Troubleshooting ==
----
 
== Teil 2: Datenbank-Backup System (SQLite) ==
 
=== Übersicht ===
'''Zweck:''' Zwei-Schicht-Backup-Strategie für Calibre/Calibre-Web Datenbanken
 
'''Problem:''' <code>/data</code> wird via <code>--one-file-system</code> vom OS-Backup ausgeschlossen
 
'''Lösung:''' Separate DB-Backups mit unterschiedlichen Retention-Zeiten
 
=== Warum separates DB-Backup? ===
'''Hintergrund:'''
 
* Calibre-Bibliothek liegt auf <code>/data/ebooks/</code> (257GB E-Books + 50MB metadata.db)
* Calibre-Web Config liegt auf <code>/data/ebooks-config/</code> (87GB Caches + 5MB app.db)
* <code>/data</code> ist ein separates RAID6-Array (52TB) und wird vom NVMe-Backup ausgeschlossen
 
'''Backup-Strategie:'''
 
* '''E-Books selbst:''' NICHT gebackupt (257GB, zu groß, regenerierbar aus Quellen)
* '''Datenbanken:''' KRITISCH für Recovery, nur ~70MB
* '''Best Practice:''' SQLite-DBs benötigen konsistente Backups via <code>sqlite3 .backup</code>
 
=== Zwei-Schicht-Architektur ===
 
==== Layer 1: Daily Safety Backup (NVMe) ====
'''Zweck:''' Schnelles Recovery bei CWA-Problemen oder Fehlkonfiguration
 
'''Eigenschaften:'''
 
* '''Ziel:''' <code>/mnt/nvme_backup/_data_dbs/</code>
* '''Retention:''' 7 Tage (tägliche Ordner: YYYY-MM-DD)
* '''Zeitplan:''' Täglich um 03:30 Uhr (nach Haupt-Backup)
* '''Größe:''' ~70MB pro Backup
* '''Service:''' <code>daily-db-backup.service</code> + <code>daily-db-backup.timer</code>
 
'''Gebackupte Dateien:'''
 
* <code>calibre_metadata</code> - <code>/data/ebooks/metadata.db</code> (50MB)
* <code>calibre_prefs</code> - <code>/data/ebooks/metadata_db_prefs_backup.json</code> (16KB)
* <code>cwa_app</code> - <code>/data/ebooks-config/app.db</code> (5MB)
* <code>cwa_main</code> - <code>/data/ebooks-config/cwa.db</code> (15MB)
 
'''Backup-Methode:'''
 
* SQLite-DBs: <code>sqlite3 $src ".backup $dest"</code> + Integrity-Check
* JSON-Dateien: Simple <code>cp -p</code>
 
==== Layer 2: Weekly Archive Backup (RAID→RAID) ====
'''Zweck:''' Langzeit-Absicherung gegen Hardware-Fehler, tiefere Historie
 
'''Eigenschaften:'''
 
* '''Ziel:''' <code>/data2/db-archive/</code>
* '''Retention:''' 4 Wochen (Ordner: YYYY-Wxx)
* '''Zeitplan:''' Sonntag 04:00 Uhr
* '''Größe:''' ~103MB pro Archiv (inkl. Backups + Logs)
* '''Service:''' <code>weekly-archive-backup.service</code> + <code>weekly-archive-backup.timer</code>
 
'''Gebackupte Dateien (erweitert):'''
 
* Alle aus Daily Backup PLUS:
* <code>calibre_metadata_backup</code> - <code>/data/ebooks/metadata.db.backup-*</code> (Wildcard)
* <code>cwa_app_backup</code> - <code>/data/ebooks-config/app.db.backup-*</code> (Wildcard)
* <code>cwa_logs</code> - <code>/data/ebooks-config/calibre-web.log*</code> (Diagnose)
 
'''Vorteile:'''
 
* RAID-zu-RAID: Besserer Hardware-Schutz als NVMe→HDD
* Wildcard-Gruppen: Automatisches Backup aller DB-Versionen
* Wöchentlich: Weniger Overhead, längere Geschichte
 
=== Software-Komponenten ===
 
==== SystemD Services (Daily Backup) ====
 
* '''Service:''' <code>daily-db-backup.service</code>
* '''Timer:''' <code>daily-db-backup.timer</code> (03:30 Uhr täglich)
* '''Script:''' <code>/usr/local/sbin/daily-db-backup</code>
* '''Logs:''' <code>/mnt/nvme_backup/_data_dbs/_logs/</code>
 
==== SystemD Services (Weekly Backup) ====
 
* '''Service:''' <code>weekly-archive-backup.service</code>
* '''Timer:''' <code>weekly-archive-backup.timer</code> (Sonntag 04:00 Uhr)
* '''Script:''' <code>/usr/local/sbin/weekly-archive-backup</code>
* '''Logs:''' <code>/data2/db-archive/_logs/</code>
 
=== Backup-Ablauf ===
 
==== Daily Backup (03:30 Uhr) ====
 
# '''Backup-Ordner erstellen:''' <code>/mnt/nvme_backup/_data_dbs/YYYY-MM-DD/</code>
# '''Für jede Datenbank:'''
#* SQLite: <code>sqlite3 .backup</code> + <code>PRAGMA integrity_check</code>
#* JSON: <code>cp -p</code> mit Timestamp-Erhalt
# '''Retention:''' Löscht Backups älter als 7 Tage
# '''Log:''' Schreibt detailliertes Log nach <code>_logs/</code>
 
==== Weekly Backup (Sonntag 04:00 Uhr) ====
 
# '''Archiv-Ordner erstellen:''' <code>/data2/db-archive/YYYY-Wxx/</code>
# '''Haupt-DBs backupen''' (wie Daily)
# '''Wildcard-Gruppen backupen:'''
#* Sucht alle <code>*.db.backup-*</code> Dateien
#* Kopiert in Unterordner
# '''Logs archivieren:''' Alle <code>calibre-web.log*</code> für Diagnose
# '''Retention:''' Löscht Archive älter als 4 Wochen
# '''Speicherplatz-Check:''' Zeigt <code>/data2</code> Belegung
 
=== Wichtige Unterschiede zu OS-Backup ===


=== Service-Kontrolle ===
=== Service-Kontrolle ===
'''Status prüfen:''' systemctl status nvme-backup.service systemctl list-timers nvme-backup.timer


'''Logs anschauen:''' journalctl -u nvme-backup.service --no-pager -n 50 ls -lth /mnt/nvme_backup/_logs/ | head
==== Status prüfen ====
bash
<code>''# Daily Backup''
systemctl status daily-db-backup.timer
systemctl status daily-db-backup.service
ls -lth /mnt/nvme_backup/_data_dbs/_logs/ | head
''# Weekly Backup''
systemctl status weekly-archive-backup.timer
systemctl status weekly-archive-backup.service
ls -lth /data2/db-archive/_logs/ | head</code>
 
==== Manueller Start ====
bash
<code>''# Daily Backup manuell ausführen''
systemctl start daily-db-backup.service
''# Weekly Backup manuell ausführen''
systemctl start weekly-archive-backup.service</code>
 
==== Backup-Struktur anzeigen ====
bash
<code>''# Daily Backups (letzte 7)''
ls -lh /mnt/nvme_backup/_data_dbs/
''# Weekly Archive (letzte 4)''
ls -lh /data2/db-archive/
''# Detaillierter Inhalt eines Backups''
tree /mnt/nvme_backup/_data_dbs/2025-10-11/</code>
----
 
== Teil 3: Wartung und Troubleshooting ==
 
=== NVMe-Backup Troubleshooting ===
 
==== Problem 1: Service schlägt fehl mit Exit 24 ====
'''Symptom:''' Mail "NVMe Backup FEHLGESCHLAGEN", journalctl zeigt "rsync warning: some files vanished"
 
'''Ursache:''' Normale Live-System-Situation
 
'''Lösung:''' Seit 2025-10-11 toleriert das Skript Exitcode 24. Bei älteren Skript-Versionen: Neues Skript installieren.
 
==== Problem 2: Backup-Disk voll ====
'''Symptom:''' rsync schlägt fehl mit "No space left on device"
 
'''Ursache:''' Mehr als erwartete Änderungen, oder Retention zu hoch
 
'''Lösung:'''
 
bash
<code>''# KEEP von 21 auf 18 oder 15 reduzieren''
sed -i 's/KEEP=21/KEEP=18/' /usr/local/sbin/nvme-backup
''# Alte Docker-Images aufräumen''
docker system prune -a
''# Journal bereinigen''
journalctl --vacuum-time=30d</code>
 
==== Problem 3: Backup dauert sehr lange ====
'''Symptom:''' rm-Prozess läuft 15+ Minuten
 
'''Ursache:''' daily.21 hat sehr viele Dateien (Hard-Links brauchen Zeit zum Löschen)
 
'''Lösung:''' Normal, abwarten. Ext4 braucht Zeit für Millionen Inodes.
 
==== Problem 4: Verzeichnis-Timestamps sind alt ====
'''Symptom:''' "daily.0 zeigt 7. Sep, aber heute ist 11. Okt"
 
'''Ursache:''' Normal! <code>mv</code> ändert keine Directory-mtimes
 
'''Lösung:''' Logs anschauen für echte Backup-Zeiten:


'''Manueller Backup-Start:''' systemctl start nvme-backup.service
bash
<code>ls -lth /mnt/nvme_backup/_logs/</code>


'''Live-Monitor während Backup:''' watch -n 2 'systemctl status nvme-backup.service --no-pager -l -n 0 && echo && ps aux | grep -E "nvme-backup|rsync" | grep -v grep'
=== DB-Backup Troubleshooting ===


=== Hard Link Effizienz prüfen ===
==== Problem 1: SQLite Integrity-Check schlägt fehl ====
'''Apparent vs Real Size:''' du -sh /mnt/nvme_backup/daily.* du -sh --apparent-size /mnt/nvme_backup/daily.*
'''Symptom:''' Log zeigt "⚠ Integritäts-Check fehlgeschlagen"


'''Hard Link Statistik für daily.0:''' locate -r 'daily.0/.*' | wc -l
'''Ursache:''' Korrupte Datenbank im Live-System


'''Anzahl Backups:''' ls -d /mnt/nvme_backup/daily.* | wc -l
'''Lösung:'''


=== Typische Probleme ===
bash
'''Problem 1: Service schlägt fehl mit Exit 24''' '''Symptom:''' Mail "NVMe Backup FEHLGESCHLAGEN", journalctl zeigt "rsync warning: some files vanished" '''Ursache:''' Normale Live-System-Situation '''Lösung:''' Seit 2025-10-11 toleriert das Skript Exitcode 24. Bei älteren Skript-Versionen: Neues Skript installieren.
<code>''# Manuelle Integritätsprüfung''
sqlite3 /data/ebooks/metadata.db "PRAGMA integrity_check;"
''# Bei Korruption: Von älterem Backup wiederherstellen''
cp /mnt/nvme_backup/_data_dbs/2025-10-10/calibre_metadata \
    /data/ebooks/metadata.db.restored</code>


'''Problem 2: Backup-Disk voll''' '''Symptom:''' rsync schlägt fehl mit "No space left on device" '''Ursache:''' Mehr als erwartete Änderungen, oder Retention zu hoch '''Lösung:'''
==== Problem 2: Wildcard-Gruppe findet keine Dateien ====
'''Symptom:''' Log zeigt "⚠ Keine Dateien gefunden"


* KEEP von 21 auf 18 oder 15 reduzieren: sed -i 's/KEEP=21/KEEP=18/' /usr/local/sbin/nvme-backup
'''Ursache:''' Keine Backup-Dateien vorhanden (z.B. nach CWA-Neuinstallation)
* Alte Docker-Images aufräumen: docker system prune -a
* Journal bereinigen: journalctl --vacuum-time=30d


'''Problem 3: Backup dauert sehr lange''' '''Symptom:''' rm-Prozess läuft 15+ Minuten '''Ursache:''' daily.21 hat sehr viele Dateien (Hard-Links brauchen Zeit zum Löschen) '''Lösung:''' Normal, abwarten. Ext4 braucht Zeit für Millionen Inodes.
'''Lösung:''' Normal, keine Aktion nötig. Das Skript überspringt diese Gruppe.


'''Problem 4: Verzeichnis-Timestamps sind alt''' '''Symptom:''' "daily.0 zeigt 7. Sep, aber heute ist 11. Okt" '''Ursache:''' Normal! mv ändert keine Directory-mtimes '''Lösung:''' Logs anschauen für echte Backup-Zeiten: ls -lth /mnt/nvme_backup/_logs/
==== Problem 3: Backup schlägt mit Exit 1 fehl ====
'''Symptom:''' Service-Status zeigt "failed"


== --one-file-system Parameter ==
'''Ursache:''' Quell-Datenbank nicht gefunden (z.B. Docker-Container gestoppt)
'''Essentiell für korrekten Betrieb!'''


Ohne diesen Parameter würde rsync in die gemounteten RAID-Arrays traversieren:
'''Lösung:''' Prüfen ob CWA läuft:


* /data (md125, XFS, 52TB)
bash
* /data2 (md126, EXT4, 61TB)
<code>docker ps | grep calibre
ls -lh /data/ebooks-config/app.db</code>


Das würde trotz Exclude-Liste die 113TB RAID-Daten mit backupen und die Backup-HDD in Sekunden füllen.
=== Wiederherstellung (Recovery) ===


'''Verifikation:''' grep "one-file-system" /usr/local/sbin/nvme-backup
==== Daily Backup Recovery (schnell) ====
'''Szenario:''' CWA-Datenbank nach Update korrupt


== Hard Link Rotation (21 Tage) ==
bash
'''Backup-Generationen:'''
<code>''# 1. CWA stoppen''
docker stop calibre-web
''# 2. Backup wiederherstellen (gestern)''
cp /mnt/nvme_backup/_data_dbs/2025-10-10/cwa_app \
    /data/ebooks-config/app.db
''# 3. Permissions korrigieren''
chown gagi:gagi /data/ebooks-config/app.db
''# 4. CWA starten''
docker start calibre-web</code>


* '''daily.0:''' Neuestes Backup (erstellt heute Nacht)
==== Weekly Archive Recovery (tiefer) ====
* '''daily.1:''' Gestern
'''Szenario:''' Calibre-Bibliothek korrupt, brauche Version von vor 3 Wochen
* '''daily.2:''' Vorgestern
* ...
* '''daily.20:''' 20 Tage alt
* '''daily.21:''' Wird beim nächsten Backup gelöscht


'''Rotation-Prozess:'''
bash
<code>''# 1. Verfügbare Archive anzeigen''
ls -lh /data2/db-archive/
''# 2. Gewünschte Woche finden (z.B. 2025-W38)''
ls -lh /data2/db-archive/2025-W38/
''# 3. Backup wiederherstellen''
cp /data2/db-archive/2025-W38/calibre_metadata \
    /data/ebooks/metadata.db
''# 4. Permissions''
chown gagi:gagi /data/ebooks/metadata.db
''# 5. Calibre restarten (falls Container läuft)''
docker restart calibre</code>


# daily.21 wird gelöscht (falls vorhanden)
==== Vollständige System-Wiederherstellung (NVMe) ====
# Alle Verzeichnisse werden um 1 hochgezählt (20→21, 19→20, ..., 0→1)
'''Szenario:''' NVMe-SSD versagt komplett
# Neues daily.0 wird erstellt
# rsync füllt daily.0 mit aktuellem System-Stand


'''Erste Löschung:''' Erfolgt erst nach 21 vollständigen Backup-Zyklen (3 Wochen nach Inbetriebnahme).
bash
<code>''# 1. Neue NVMe-SSD einbauen''
''# 2. Debian 13 Minimal installieren''
''# 3. Backup-HDD mounten''
mount /dev/sdar1 /mnt/backup
''# 4. System wiederherstellen''
rsync -aAXH --numeric-ids /mnt/backup/daily.0/ /mnt/newsystem/
''# 5. Bootloader neu installieren''
chroot /mnt/newsystem
grub-install /dev/nvme0n1
update-grub
exit
''# 6. Reboot''
reboot</code>
----


== Performance-Charakteristika ==
== Teil 4: Performance und Kapazität ==
'''Erstes Backup:''' ~130GB in 1,5 Stunden (Vollübertragung) '''Folge-Backups:''' ~5-40GB in 15-60 Minuten (nur Änderungen) '''CPU-Verbrauch:''' ~4 Minuten CPU-Zeit pro Backup '''Memory Peak:''' ~5.7GB während Backup '''Hard Link Effizienz:''' 98-99% Dateien verlinkt zwischen Generationen '''Durchschnittlicher Speicherverbrauch:''' 37GB real pro Generation
 
=== NVMe-Backup Performance ===
 
* '''Erstes Backup:''' ~130GB in 1,5 Stunden (Vollübertragung)
* '''Folge-Backups:''' ~5-40GB in 15-60 Minuten (nur Änderungen)
* '''CPU-Verbrauch:''' ~4 Minuten CPU-Zeit pro Backup
* '''Memory Peak:''' ~5.7GB während Backup
* '''Hard Link Effizienz:''' 98-99% Dateien verlinkt zwischen Generationen
* '''Durchschnittlicher Speicherverbrauch:''' 37GB real pro Generation


'''Rotation (rm -rf daily.21):'''
'''Rotation (rm -rf daily.21):'''


* Dauer: 5-15 Minuten
* '''Dauer:''' 5-15 Minuten
* CPU: 20-30% eines Cores
* '''CPU:''' 20-30% eines Cores
* Grund: Millionen Hard-Links müssen aufgelöst werden
* '''Grund:''' Millionen Hard-Links müssen aufgelöst werden
 
=== DB-Backup Performance ===
 
* '''Daily Backup:''' ~3 Sekunden (4 Dateien, 70MB)
* '''Weekly Backup:''' ~5 Sekunden (7 Items, 103MB)
* '''CPU-Verbrauch:''' Minimal (<1% Core)
* '''Speicherverbrauch:''' ~500MB pro Woche


== Kapazitäts-Management ==
=== Kapazitäts-Management ===


=== Speicherplatz-Überwachung ===
==== NVMe-Backup ====
'''Aktuelle Nutzung (typisch):''' 330-400GB für 21 Generationen '''Projektion 21 Tage:''' ~777GB (85% der 916GB HDD) '''Sicherheitspuffer:''' ~140GB für Variabilität '''Überwachung:''' Automatisch via Mail nach jedem Backup


=== Notfall-Maßnahmen bei Speicherknappheit ===
* '''Aktuelle Nutzung (typisch):''' 330-400GB für 21 Generationen
'''Option 1: Retention reduzieren''' sed -i 's/KEEP=21/KEEP=18/' /usr/local/sbin/nvme-backup
* '''Projektion 21 Tage:''' ~777GB (85% der 916GB HDD)
* '''Sicherheitspuffer:''' ~140GB für Variabilität
* '''Überwachung:''' Automatisch via Mail nach jedem Backup


'''Option 2: System-Dateien aufräumen'''
==== DB-Backups ====


* Docker: docker system prune -a
* '''Daily (NVMe):''' 7 × 70MB = ~490MB
* Journal: journalctl --vacuum-time=30d
* '''Weekly (RAID):''' 4 × 103MB = ~412MB
* APT: apt clean && apt autoclean
* '''Total:''' <1GB für beide Backup-Layer


'''Option 3: Manuelle Backup-Löschung''' rm -rf /mnt/nvme_backup/daily.20 rm -rf /mnt/nvme_backup/daily.19
'''Notfall-Maßnahmen bei Speicherknappheit (NVMe-Backup):'''


== Integration in Gesamtsystem ==
Option 1: Retention reduzieren


=== Drei-Schicht-Backup-Architektur ===
bash
<code>sed -i 's/KEEP=21/KEEP=18/' /usr/local/sbin/nvme-backup</code>
Option 2: System-Dateien aufräumen


# '''RAID6-Arrays:''' Live-Redundanz für Nutzdaten (/data, /data2)
bash
# '''NVMe-Backup:''' OS-Recovery mit Service-Konfiguration (21 Tage Historie)
<code>docker system prune -a
# '''Mail-Monitoring:''' Automatische Überwachung mit Statistiken
journalctl --vacuum-time=30d
apt clean && apt autoclean</code>
Option 3: Manuelle Backup-Löschung


=== Optimierte Ressourcen-Aufteilung ===
bash
<code>rm -rf /mnt/nvme_backup/daily.20
rm -rf /mnt/nvme_backup/daily.19</code>
----


* '''RAID-Schutz:''' 113TB Nutzdaten mit Hardware-Redundanz
== Teil 5: Integration in Gesamtsystem ==
* '''NVMe-Backup:''' 130GB System-Recovery mit 3-Wochen-Historie
* '''Hard Link Effizienz:''' 777GB für 21 Vollbackups (statt 2.7TB)


== Disaster Recovery ==
=== Drei-Schicht-Backup-Architektur ===
'''Layer 1: RAID6-Arrays (Live-Redundanz)'''


=== Vollständige System-Wiederherstellung ===
* <code>/data</code> (md125, XFS, 52TB) - E-Books, Medien
'''Szenario:''' NVMe-SSD versagt komplett
* <code>/data2</code> (md126, EXT4, 61TB) - Backups, Archive
* '''Zweck:''' Hardware-Redundanz gegen Festplattenausfall


'''Wiederherstellung:'''
'''Layer 2: NVMe-Backup (System-Recovery)'''


# Neue NVMe-SSD einbauen
* Ziel: <code>/mnt/nvme_backup</code> (1TB HDD)
# Debian 13 Minimal installieren
* Retention: 21 Tage
# Backup-HDD mounten
* '''Zweck:''' Vollständige OS-Wiederherstellung, 3-Wochen-Historie
# rsync von daily.0 zurück auf /
# Bootloader neu installieren
# Reboot


'''Beispiel-Befehle:''' mount /dev/sdar1 /mnt/backup rsync -aAXH --numeric-ids /mnt/backup/daily.0/ /mnt/newsystem/ chroot /mnt/newsystem grub-install /dev/nvme0n1 update-grub
'''Layer 3: DB-Backups (Datenbank-Schutz)'''


=== Einzeldatei-Wiederherstellung ===
* Daily: <code>/mnt/nvme_backup/_data_dbs/</code> (7 Tage)
'''Szenario:''' Versehentlich Datei gelöscht
* Weekly: <code>/data2/db-archive/</code> (4 Wochen)
* '''Zweck:''' SQLite-konsistente Backups für Calibre/CWA


'''Wiederherstellung:'''
=== Optimierte Ressourcen-Aufteilung ===


# Finde Datei in einem der daily.* Backups
* '''RAID-Schutz:''' 113TB Nutzdaten mit Hardware-Redundanz
# Kopiere zurück ins Live-System
* '''NVMe-Backup:''' 130GB System-Recovery mit 3-Wochen-Historie
* '''DB-Backups:''' <1GB für 7+28 Tage Datenbank-Historie
* '''Hard Link Effizienz:''' 777GB für 21 Vollbackups (statt 2.7TB)


'''Beispiel:''' cp /mnt/nvme_backup/daily.1/etc/apache2/sites-available/mysite.conf /etc/apache2/sites-available/
=== Zeitplan-Koordination ===
<code>03:05 Uhr: NVMe-Backup (OS-Level) startet
03:30 Uhr: Daily DB-Backup startet (nach OS-Backup)
04:00 Uhr: Weekly Archive-Backup (nur Sonntag)</code>
'''Grund:''' DB-Backups laufen NACH dem Haupt-Backup, um Konflikte zu vermeiden.
----


== Changelog ==
== Changelog ==
'''v3.0 (2025-10-11):'''
* Zwei-Schicht-DB-Backup-System hinzugefügt
* Daily Safety Backup (NVMe, 7 Tage)
* Weekly Archive Backup (RAID→RAID, 4 Wochen)
* SQLite <code>.backup</code> API für konsistente DB-Kopien
* Separate SystemD Services/Timers für DB-Backups
* Dokumentation komplett überarbeitet und erweitert
'''v2.0 (2025-10-11):'''
'''v2.0 (2025-10-11):'''


Zeile 1.313: Zeile 1.617:
* Mail-Benachrichtigungen implementiert
* Mail-Benachrichtigungen implementiert
* Hard-Link-Backup produktiv
* Hard-Link-Backup produktiv
----'''Ende der Dokumentation v3.0'''


= STORE2 NVME Disaster Recovery Dokumentation =
= STORE2 NVME Disaster Recovery Dokumentation =
Zeile 1.700: Zeile 2.006:
tail -f /mnt/nvme_backup/_logs/run-*.log
tail -f /mnt/nvme_backup/_logs/run-*.log


= HDD als NTFS unter Linux richtig formatieren2 =
= HDD als NTFS unter Linux richtig formatieren =
Szenario: Raid-Platte geht noch, liefert aber sporadische Fehler in dmesg z.B. -> wird im Raid ersetzt -> ist dann "über" -> kann als Serien-Sammelplatte noch verwendet werden
Szenario: Raid-Platte geht noch, liefert aber sporadische Fehler in dmesg z.B. -> wird im Raid ersetzt -> ist dann "über" -> kann als Serien-Sammelplatte noch verwendet werden



Aktuelle Version vom 11. Oktober 2025, 18:28 Uhr

STORE2 NETZWERK-ARCHITEKTUR - KURZREFERENZ

KRITISCHE ARCHITEKTUR-GRUNDLAGEN

Drei parallele Zugriffswege:

  1. Apache Reverse Proxy (Port 443/80) → Domain dergagi.changeip.org
  2. Traefik Reverse Proxy (Port 8444/81) → Nextcloud nc.dergagi9.duckdns.org:8444
  3. Direkte HTTP-Ports → Dienste ohne Proxy

APACHE VIRTUALHOST STRUKTUR (PORT 443)

Zwei VirtualHosts auf Port 443:

  • 000-catchall-443.conf (ServerName: catchall.local, default)
  • 000-website-dergagi-443.conf (ServerName: dergagi.changeip.org)

KRITISCH: Beide VirtualHosts haben identische ProxyPass-Regeln, weil catchall als Default viele Requests abfängt.

Aktive ProxyPass-Routen:

/w/     → http://127.0.0.1:8088   (MediaWiki, Docker)
/yt4k/  → http://127.0.0.1:8443   (YT4K, SystemD)
/ombi/  → http://127.0.0.1:3579/ombi/  (Ombi, Docker)
/cwa    → http://127.0.0.1:8084   (Calibre-Web, Docker)
/api    → http://127.0.0.1:8443/api

Port 444: Home Assistant Proxy → http://127.0.0.1:8123

KRITISCHE ERKENNTNISSE (LESSONS LEARNED)

1. conf-enabled Dateien sind gefährlich

Problem: /etc/apache2/conf-enabled/yt4k-*.conf überschrieb VirtualHost-Configs mit alten Ports. Lösung: ALLE Proxy-Regeln direkt in VirtualHosts definieren, KEINE separaten conf-Dateien verwenden.

2. Apache reload ist unzuverlässig

Bei ProxyPass-Änderungen: systemctl restart apache2 (nicht reload!) Grund: reload cached manchmal alte Backend-Ports.

3. SystemD Override-Dateien prüfen

Prüfen mit: systemctl cat service.service YT4K Beispiel: Override in /etc/systemd/system/yt4k.service.d/90-force.conf änderte Port auf 8443.

4. Backup-Dateien aus sites-enabled entfernen

Dateien wie .bak, .tmp, .new werden von Apache gelesen und verursachen Konflikte.

WICHTIGSTE DIENSTE & PORTS

Über Apache Proxy (HTTPS):

  • MediaWiki: https://dergagi.changeip.org/w/
  • YT4K: https://dergagi.changeip.org/yt4k/
  • Ombi: https://dergagi.changeip.org/ombi/

Direkt HTTP (ohne Proxy):

  • Emby: http://dergagi.changeip.org:8096
  • n8n: http://dergagi.changeip.org:5678
  • Grafana: http://dergagi.changeip.org:3000
  • HomeBox: http://dergagi.changeip.org:3100
  • Koel: http://dergagi.changeip.org:6680
  • Uptime Kuma: http://dergagi.changeip.org:3001

Traefik (Nextcloud):

  • Nextcloud: https://nc.dergagi9.duckdns.org:8444

TROUBLESHOOTING ESSENTIALS

503 Service Unavailable über Apache Proxy

Diagnose:

bash

# Backend läuft?
systemctl status yt4k.service
ss -tlnp | grep :8443

# Backend direkt erreichbar?
curl http://127.0.0.1:8443/

# Apache Config korrekt?
grep "ProxyPass.*yt4k" /etc/apache2/sites-enabled/*.conf

# Alte conf-enabled Dateien?
ls /etc/apache2/conf-enabled/ | grep yt4k

Lösung:

bash

# Alte conf-enabled deaktivieren
a2disconf yt4k.conf
systemctl restart apache2  # RESTART!

Browser erzwingt HTTPS für HTTP-Ports

Ursache: HSTS im Browser-Cache Lösung Chrome: chrome://net-internals/#hsts → Domain dergagi.changeip.org löschen Alternative: Private/Incognito Mode

Apache Config Änderungen

Checkliste:

  1. Backup: cp config.conf config.conf.backup-$(date +%Y%m%d)
  2. Änderung vornehmen
  3. Test: apache2ctl configtest
  4. RESTART: systemctl restart apache2 (nicht reload!)
  5. Dienst testen: curl -k https://dergagi.changeip.org/path/

SYSTEMD SERVICES (NATIVE/PYTHON)

YT4K Upscaler:

  • Port: 8443 (NICHT 8010!)
  • Service: yt4k.service
  • Path: /srv/yt4k/
  • User: www-data

n8n:

  • Port: 5678
  • Service: n8n.service
  • Path: /opt/n8n/
  • User: gagi

Emby:

  • Port: 8096
  • Service: emby-server.service
  • Path: /opt/emby-server/, /var/lib/emby/
  • User: emby

Heatmap:

  • Port: 8020
  • Service: heatmap8020.service
  • Path: /opt/heatmap8020/
  • User: root

DOCKER WICHTIGSTE CONTAINER

Host Network (direkt):

  • homeassistant (Port 8123)
  • grafana-system (Port 3000)
  • prometheus-system (Port 9090)

Bridge mit Port-Mapping:

  • nextcloud-app (8086:80, über Traefik 8444)
  • mediawiki (8088:80)
  • koel (6680:80)
  • ombi (3579:3579)
  • uptime-kuma (3001:3001)

Traefik + Nextcloud:

  • Netzwerk: proxy (172.27.0.0/16)
  • traefik-nc: Port 8444 (HTTPS), 81 (HTTP), 8082 (Dashboard)
  • nextcloud-app: In zwei Netzwerken (proxy + nextcloud_nextcloud-net)

SSL/TLS ZERTIFIKATE

Apache (Certbot):

  • Domain: dergagi.changeip.org
  • Path: /etc/letsencrypt/live/dergagi.changeip.org/
  • Gültig bis: 29.12.2025

Traefik (ACME):

  • Domain: Wildcard *.dergagi9.duckdns.org
  • Path: /srv/traefik/letsencrypt/acme.json
  • Gültig bis: 18.11.2025

WICHTIGE PFADE

Apache Configs:     /etc/apache2/sites-enabled/
Apache Logs:        /var/log/apache2/error.log
Docker Compose:     /srv/*/docker-compose.yml
SystemD Services:   /etc/systemd/system/*.service
Backups:            /mnt/nvme_backup/ (21 Versionen)
Archive:            /root/apache-archive-*/

QUICK REFERENCE COMMANDS

bash

# Apache
apache2ctl configtest && systemctl restart apache2
apache2ctl -S  # VirtualHosts anzeigen

# Port prüfen
ss -tlnp | grep :PORT
curl http://127.0.0.1:PORT/

# Docker
docker ps
docker logs -f CONTAINER
docker compose restart

# SystemD
systemctl status SERVICE
systemctl cat SERVICE  # Inkl. Overrides!
journalctl -u SERVICE -f

REGELN FÜR ÄNDERUNGEN

  1. NIE conf-enabled Dateien für Proxies verwenden
  2. IMMER ProxyPass in beiden VirtualHosts (catchall + website) definieren
  3. IMMER systemctl restart apache2 bei Proxy-Änderungen (nicht reload)
  4. IMMER systemctl cat prüfen bei SystemD-Services (Override-Dateien!)
  5. IMMER Backend direkt testen bevor Proxy konfiguriert wird

HSTS-HINWEIS

Aktuell: KEIN HSTS-Header aktiv (bewusst deaktiviert) Grund: Flexible Nutzung von HTTP-Ports (3000, 5678, 6680, etc.) Wenn Browser HTTPS erzwingt: Browser-Cache löschen (siehe Troubleshooting)


Version: 1.0 Kurzfassung | Datum: 01.10.2025 | Basis: Vollständige Dokumentation v1.0

STORE2 NETZWERK-ARCHITEKTUR DOKUMENTATION Vollständig

Version: 1.0 | Datum: 01.10.2025 | Host: STORE2 (Debian 13 Cinnamon)


EXECUTIVE SUMMARY

STORE2 betreibt eine hybride Infrastruktur mit drei parallelen Zugriffswegen, die sorgfältig getrennt sein müssen:

  1. Apache Reverse Proxy (Port 443/80) → Hauptdomain dergagi.changeip.org
  2. Traefik Reverse Proxy (Port 8444/81) → Nextcloud nc.dergagi9.duckdns.org:8444
  3. Direkte Port-Zugriffe → Dienste ohne Proxy (HTTP)

Die Komplexität entsteht durch die Kombination aus:

  • 2 Apache VirtualHosts auf Port 443 (catchall + named)
  • Docker-basierte Dienste (24 Container)
  • SystemD-Services (4 native/Python-Apps)
  • Zwei separate Let's Encrypt Systeme (Apache/Certbot + Traefik/ACME)

Kritische Erkenntnis aus heutigem Troubleshooting: Globale Apache conf-enabled Dateien überschreiben VirtualHost-Konfigurationen. Proxy-Routen müssen direkt in VirtualHosts definiert werden, NICHT in separaten conf-Dateien.


1. NETZWERK-ARCHITEKTUR ÜBERSICHT

1.1 Die drei Zugriffswege

Internet
   |
   |-- Port 443/80 --> Apache --> Reverse Proxy --> Interne Dienste
   |
   |-- Port 8444 --> Traefik --> Nextcloud (Port 8086)
   |
   |-- Direkte Ports (3000, 5678, 6680, 8092, etc.) --> HTTP-Dienste

1.2 Apache VirtualHost Struktur (Port 443)

Apache nutzt zwei VirtualHosts, die beide auf Port 443 lauschen:

A) 000-catchall-443.conf (Default VirtualHost)

  • ServerName: catchall.local
  • Funktion: Fängt Requests ohne spezifischen Host ab
  • ProxyPass: /w/ (MediaWiki), /yt4k/, /ombi/
  • Problem: Ist als *default* konfiguriert, wird deshalb bevorzugt behandelt

B) 000-website-dergagi-443.conf (Named VirtualHost)

  • ServerName: dergagi.changeip.org
  • Funktion: Expliziter Host-Match
  • ProxyPass: /yt4k/, /api, /ombi/, /w/, /cwa
  • Enthält zusätzlich: MediaWiki Rewrite-Rules, PHP-FPM Handler

Wichtig: Beide VirtualHosts haben identische ProxyPass-Regeln für /yt4k/ und /ombi/, um sicherzustellen, dass die Dienste unabhängig vom gewählten VirtualHost erreichbar sind.

1.3 Port 444 - Home Assistant

Separater VirtualHost auf Port 444 für Home Assistant:

  • URL: https://dergagi.changeip.org:444
  • Proxy zu: localhost:8123
  • Besonderheit: WebSocket-Support für /api/websocket

2. DIENSTE-ÜBERSICHT

2.1 Vollständige Dienste-Tabelle

2.2 Port-Belegung (alle lauschenden Ports)

80      Apache HTTP (Redirect zu HTTPS)
81      Traefik HTTP (Let's Encrypt Challenge)
443     Apache HTTPS (Hauptdomain)
444     Apache HTTPS (Home Assistant)
3000    Grafana System Monitoring
3001    Uptime Kuma
3100    HomeBox Inventar
3579    Ombi (intern, Apache Proxy)
5678    n8n Automation
6680    Koel Music Streaming
8020    Heatmap Generator
8080    LibreSpeed
8082    Traefik Dashboard
8084    Calibre-Web (intern, Apache Proxy)
8086    Nextcloud App (intern, Traefik Proxy)
8087    InfluxDB (Speedtest Daten)
8088    MediaWiki (intern, Apache Proxy)
8092    Speedtest Tracker
8096    Emby Media Server
8123    Home Assistant (intern, Apache Proxy Port 444)
8443    YT4K Upscaler (intern, Apache Proxy)
8444    Traefik HTTPS (Nextcloud)
9000    Portainer (nur Tailscale + localhost)
9090    Prometheus System
9100    Node Exporter
19998   Netdata

3. APACHE REVERSE PROXY SETUP

3.1 Haupt-Konfigurationsdateien

Aktive sites-enabled:

000-catchall-443.conf       → Default VirtualHost, Port 443
000-website-dergagi-443.conf → Named VirtualHost, Port 443
00-redirect-80.conf          → HTTP zu HTTPS Redirect
homeassistant-444.conf      → Home Assistant, Port 444
le-webroot-80.conf          → Let's Encrypt Webroot

Wichtig: Keine conf-enabled Dateien mehr aktiv! Alle Proxy-Regeln sind direkt in den VirtualHosts definiert.

3.2 Apache Proxy-Routen (Port 443)

000-catchall-443.conf ProxyPass-Regeln:

apache

ProxyPass        /w/     http://127.0.0.1:8088/
ProxyPassReverse /w/     http://127.0.0.1:8088/

ProxyPass        /yt4k/  http://127.0.0.1:8443/ retry=0
ProxyPassReverse /yt4k/  http://127.0.0.1:8443/

ProxyPass        /ombi/  http://127.0.0.1:3579/ombi/ retry=0
ProxyPassReverse /ombi/  http://127.0.0.1:3579/ombi/

000-website-dergagi-443.conf ProxyPass-Regeln:

apache

ProxyPass        /api    http://127.0.0.1:8443/api retry=0
ProxyPassReverse /api    http://127.0.0.1:8443/api

ProxyPass        /yt4k/  http://127.0.0.1:8443/ retry=0
ProxyPassReverse /yt4k/  http://127.0.0.1:8443/

ProxyPass        /ombi/  http://127.0.0.1:3579/ombi/ retry=0
ProxyPassReverse /ombi/  http://127.0.0.1:3579/ombi/

ProxyPass        /w/     http://127.0.0.1:8088/
ProxyPassReverse /w/     http://127.0.0.1:8088/

<Location /cwa>
    ProxyPass        http://127.0.0.1:8084/
    ProxyPassReverse http://127.0.0.1:8084/
</Location>

Zusätzliche Features:

  • MediaWiki Short URLs: /wiki//w/index.php?title=
  • PHP-FPM Handler für .php Dateien
  • Security Headers (X-Content-Type-Options, X-Frame-Options, Referrer-Policy)
  • Kein HSTS-Header (bewusst deaktiviert für flexible Port-Nutzung)

3.3 SSL/TLS Konfiguration (Apache)

Zertifikat: /etc/letsencrypt/live/dergagi.changeip.org/

  • Typ: Let's Encrypt (via Certbot)
  • Ausgestellt: 30. September 2025
  • Gültig bis: 29. Dezember 2025
  • Erneuerung: Automatisch via Certbot

SSL-Engine:

apache

SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/dergagi.changeip.org/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/dergagi.changeip.org/privkey.pem

Genutzt von:

  • 000-catchall-443.conf
  • 000-website-dergagi-443.conf
  • homeassistant-444.conf

4. TRAEFIK REVERSE PROXY (NEXTCLOUD)

4.1 Traefik v3.5 Setup

Container: traefik-nc Image: traefik:v3.5 Netzwerk: proxy (Bridge, 172.27.0.0/16)

Port-Mapping:

8444 (extern) → 443 (intern)    HTTPS für Nextcloud
81   (extern) → 80  (intern)    HTTP für Let's Encrypt Challenge
8082 (extern) → 8080 (intern)   Traefik Dashboard

4.2 Nextcloud Docker Compose

Container: nextcloud-app Image: nextcloud:31.0.9 Port: 8086:80 (intern)

Netzwerke:

  • nextcloud_nextcloud-net (Bridge, 172.26.0.0/16) → Verbindung zur DB
  • proxy (Bridge, 172.27.0.0/16) → Verbindung zu Traefik

Environment Variables:

yaml

OVERWRITEPROTOCOL: https
OVERWRITEHOST: nc.dergagi9.duckdns.org:8444
NEXTCLOUD_TRUSTED_DOMAINS: nc.dergagi9.duckdns.org:8444
TRUSTED_PROXIES: 172.16.0.0/12 192.168.0.0/16 10.0.0.0/8

Traefik Labels:

yaml

traefik.enable: true
traefik.http.routers.nextcloud.rule: Host(`nc.dergagi9.duckdns.org`)
traefik.http.routers.nextcloud.entrypoints: websecure
traefik.http.routers.nextcloud.tls: true
traefik.http.routers.nextcloud.tls.certresolver: letsencrypt
traefik.http.services.nextcloud.loadbalancer.server.port: 80

4.3 SSL/TLS (Traefik)

Zertifikat: Wildcard *.dergagi9.duckdns.org

  • Typ: Let's Encrypt (via Traefik ACME)
  • Speicherort: /srv/traefik/letsencrypt/acme.json
  • Ausgestellt: 20. August 2025
  • Gültig bis: 18. November 2025
  • Erneuerung: Automatisch via Traefik

Zugriff:

https://nc.dergagi9.duckdns.org:8444

5. DOCKER CONTAINER ÜBERSICHT

5.1 Container nach Netzwerk

Host Network (direkter Host-Zugriff):

  • homeassistant (Home Assistant Core)
  • grafana-system (System Monitoring, Port 3000)
  • prometheus-system (Metriken, Port 9090)
  • node-simple (Node Exporter, Port 9100)
  • addon_5c53de3b_esphome (ESPHome Add-on)
  • addon_core_matter_server (Matter Server)
  • addon_a0d7b954_tailscale (Tailscale Add-on)
  • hassio_multicast (Multicast DNS)

Bridge Networks:

  • bridge (172.17.0.0/16): homebox, ombi, hassio_supervisor
  • proxy (172.27.0.0/16): traefik-nc, nextcloud-app
  • nextcloud_nextcloud-net (172.26.0.0/16): nextcloud-app, nextcloud-db
  • koel_default (172.23.0.0/16): koel, koel-db
  • mediawiki-clean-final_default (192.168.80.0/20): mw-clean-final, mw-clean-final-db
  • cwa_default (172.20.0.0/16): calibre-web-automated
  • uptime-kuma_default (192.168.32.0/20): uptime-kuma
  • speedtest-tracker-new_default (172.24.0.0/16): speedtest-tracker-new, speedtest-influxdb-v2
  • portainer-net (192.168.160.0/20): portainer
  • hassio (172.30.32.0/23): Home Assistant Add-ons

5.2 Kritische Container mit Restart-Policy

Alle produktiven Container nutzen: restart: unless-stopped

Ausnahmen (restart: no):

  • Home Assistant Add-ons (werden von Supervisor verwaltet)

6. SYSTEMD SERVICES (NATIVE/PYTHON)

6.1 Emby Media Server

Type: Native Debian Installation (Version 4.9.1.31) Port: 8096 (HTTP), 8920 (HTTPS, nicht konfiguriert) Service: emby-server.service User: emby

Pfade:

  • Binary: /opt/emby-server/
  • Daten: /var/lib/emby/

FFmpeg Override:

ExecStart=/opt/emby-server/system/EmbyServer -programdata /var/lib/emby \
  -ffdetect /opt/emby-server/bin/ffdetect \
  -ffmpeg /usr/bin/ffmpeg \
  -ffprobe /usr/bin/ffprobe

6.2 YT4K Upscaler (FastAPI)

Type: Python FastAPI + Uvicorn Port: 8443 (HTTP) Service: yt4k.service User: www-data WorkingDirectory: /srv/yt4k/

ExecStart (via override):

bash

/srv/yt4k/.venv/bin/uvicorn --app-dir /srv/yt4k app:app \
  --host 0.0.0.0 --port 8443 --workers 2 --log-level info

Wichtig: Läuft auf 0.0.0.0:8443, nicht auf 127.0.0.1:8010 (alte Config)!

6.3 n8n Automation

Type: Node.js App Port: 5678 (HTTP) Service: n8n.service User: gagi WorkingDirectory: /opt/n8n/

Environment:

N8N_PORT=5678
N8N_HOST=0.0.0.0
N8N_USER_FOLDER=/opt/n8n

ExecStart:

bash

/usr/local/bin/n8n

6.4 Heatmap Generator (FastAPI)

Type: Python FastAPI + Uvicorn Port: 8020 (HTTP) Service: heatmap8020.service User: root WorkingDirectory: /opt/heatmap8020/

Environment:

MPLBACKEND=Agg  # Matplotlib ohne Display

ExecStart:

bash

/opt/heatmap8020/.venv/bin/uvicorn app:app \
  --host 0.0.0.0 --port 8020 --proxy-headers

7. TAILSCALE INTEGRATION

IP: 100.108.194.126 Hostname: store2 Status: Active

Verwendung:

  • Portainer: http://100.108.194.126:9000 (einziger Zugriff)
  • Keine Tailscale Serve/Funnel Konfiguration aktiv

Andere Tailscale Nodes:

  • myth (Windows, 100.98.212.121) - Active
  • silvaner (Windows, 100.120.162.83) - Active
  • Weitere Nodes offline

8. MONITORING & METRICS

8.1 Grafana System Monitoring

Container: grafana-system Port: 3000 (Host Network) Datenquelle: Prometheus System (Port 9090)

Metriken:

  • CPU, RAM, Disk I/O via node-exporter-system (Port 9100)
  • Direkt vom Host via Host Network

8.2 Uptime Kuma

Container: uptime-kuma Image: louislam/uptime-kuma:1.23.13-alpine Port: 3001 Daten: /opt/uptime-kuma/data

Funktion:

  • HTTP(s) Checks für alle kritischen Dienste
  • Ping Tests
  • E-Mail Alerts bei Ausfällen

8.3 Netdata Real-Time Monitoring

Type: Native Installation Port: 19998 Zugriff: http://dergagi.changeip.org:19998

Metriken:

  • Real-time System Performance
  • Container Monitoring
  • Network Traffic
  • Disk I/O

9. BACKUP & REDUNDANZ

9.1 NVMe System Backup

Timer: nvme-backup.timer Schedule: Täglich um 03:08 Uhr Technologie: rsync mit --link-dest

Quellen: System-Partitionen (NVMe) Ziel: /mnt/nvme_backup Aufbewahrung: 21 Versionen (Hard-Link-Snapshots)

Wichtig: --one-file-system verhindert Backup der 113TB RAID-Arrays!

9.2 RAID Monitoring

Arrays:

  • /data (RAID6)
  • /data2 (RAID6)

Monitoring:

  • mdadm (/etc/mdadm/mdadm.conf)
  • smartd (/etc/smartd.conf)
  • Alert-Script: /usr/local/sbin/health-alert.sh

Besonderheit: SMART-Fehler ID 197 (CurrentPendingSector) wird ignoriert (RAID-typisch, nicht kritisch).


10. TROUBLESHOOTING GUIDE

10.1 Häufige Probleme & Lösungen

Problem: Dienst über Apache Proxy gibt 503 Service Unavailable

Symptome:

503 Service Unavailable
AH00957: http: attempt to connect to 127.0.0.1:PORT failed

Ursachen & Lösungen:

  1. Backend läuft nicht:

bash

# Prüfen
systemctl status yt4k.service
docker ps | grep mediawiki

# Starten
systemctl start yt4k.service
docker start mw-clean-final
  1. Falscher Port in Apache Config:

bash

# Prüfen welcher Port tatsächlich lauscht
ss -tlnp | grep :8443

# Apache Config prüfen
grep "ProxyPass.*yt4k" /etc/apache2/sites-enabled/*.conf

# Port korrigieren und neu laden
systemctl reload apache2
  1. Globale conf-enabled Datei überschreibt VirtualHost:

bash

# Prüfen
ls /etc/apache2/conf-enabled/

# Alte yt4k-*.conf Dateien deaktivieren
a2disconf yt4k.conf
systemctl restart apache2  # RESTART, nicht reload!

Problem: Browser erzwingt HTTPS für HTTP-Ports (HomeBox, Koel, n8n)

Symptome:

Browser zeigt "Sichere Verbindung fehlgeschlagen" für:
http://dergagi.changeip.org:3100 (HomeBox)
http://dergagi.changeip.org:6680 (Koel)

Ursache: HSTS im Browser-Cache

Lösung:

Chrome/Edge:

  1. Öffne chrome://net-internals/#hsts
  2. "Delete domain security policies"
  3. Domain: dergagi.changeip.org
  4. [Delete]

Firefox:

  1. about:preferences#privacy
  2. "Cookies und Website-Daten"
  3. "Daten verwalten..."
  4. Suche: dergagi.changeip.org
  5. "Ausgewählte entfernen"

Alternative: Nutze Private/Incognito Mode

Problem: MediaWiki API nicht erreichbar

Symptome:

/w/api.php gibt 404 oder wird zu falscher URL weitergeleitet

Lösung:

bash

# Prüfe RewriteRules
grep "RewriteRule.*api.php" /etc/apache2/sites-enabled/*.conf

# Sollte sein:
# RewriteRule ^/w/(api\.php|load\.php|rest\.php)$ - [L]

Problem: Nextcloud über Port 8444 nicht erreichbar

Symptome:

https://nc.dergagi9.duckdns.org:8444 → Connection refused

Diagnose:

bash

# Traefik läuft?
docker ps | grep traefik-nc

# Port 8444 lauscht?
ss -tlnp | grep :8444

# Traefik Logs
docker logs traefik-nc --tail 50

# Nextcloud Container läuft?
docker ps | grep nextcloud-app

# Netzwerk korrekt?
docker inspect nextcloud-app | grep -A 10 Networks

Lösung:

bash

cd /srv/nextcloud
docker compose restart

10.2 Apache Reload vs Restart

WICHTIG: Bei Proxy-Änderungen immer RESTART, nicht reload!

bash

# NUR für Header/Rewrite-Änderungen:
systemctl reload apache2

# Für ProxyPass-Änderungen:
systemctl restart apache2

Grund: reload cached manchmal alte ProxyPass-Werte.

10.3 Docker Container Restart-Reihenfolge

Bei kompletten Neustarts (z.B. nach Server-Reboot):

  1. Datenbank-Container zuerst:

bash

docker start nextcloud-db mw-clean-final-db koel-db
sleep 5
  1. Dann App-Container:

bash

docker start nextcloud-app mw-clean-final koel
  1. Traefik zuletzt:

bash

docker start traefik-nc

11. LESSONS LEARNED (01.10.2025)

11.1 Kritische Erkenntnisse

  1. Globale conf-enabled Dateien sind gefährlich:
    • /etc/apache2/conf-enabled/yt4k-proxy-root.conf überschrieb VirtualHost-Configs
    • Enthielt alte Port-Nummern (8010 statt 8443)
    • Wurde trotz korrekter VirtualHost-Config verwendet
    • Best Practice: Alle Proxy-Regeln direkt in VirtualHosts definieren
  2. Apache Reload ist nicht ausreichend:
    • Bei ProxyPass-Änderungen: systemctl restart apache2
    • reload cached manchmal alte Backend-Ports
    • Führte zu 1 Stunde Debugging
  3. Zwei VirtualHosts auf Port 443 = Verwirrung:
    • 000-catchall-443.conf als *default* fängt viele Requests ab
    • 000-website-dergagi-443.conf sollte eigentlich matchen
    • Lösung: Beide mit identischen ProxyPass-Regeln ausstatten
  4. Backup-Dateien in sites-enabled verursachen Probleme:
    • .bak, .tmp, .new Dateien werden von Apache gelesen
    • Können zu Konflikten führen
    • Best Practice: Nur .conf Dateien in sites-enabled
  5. SystemD Service Override-Dateien:
    • /etc/systemd/system/yt4k.service.d/90-force.conf überschrieb Haupt-Service
    • Port 8443 statt 8010 - aber Apache zeigte auf 8010
    • Immer prüfen: systemctl cat service.service

11.2 Erfolgreiche Strategien

  1. Systematisches Debugging:
    • Port-Listening prüfen: ss -tlnp | grep :PORT
    • Backend direkt testen: curl http://127.0.0.1:PORT/
    • Apache Error Log live: tail -f /var/log/apache2/error.log
    • VirtualHost Dump: apache2ctl -S
  2. Archivierung statt Löschen:
    • Alle Backup-Dateien nach /root/apache-archive-DATE/
    • Ermöglicht schnelles Rollback
    • 81 alte Configs archiviert, System bleibt sauber
  3. Docker Netzwerk-Isolation:
    • Nextcloud in proxy + nextcloud_nextcloud-net
    • Traefik nur in proxy
    • Saubere Trennung zwischen Diensten

12. WARTUNGS-CHECKLISTEN

12.1 Vor jeder Apache-Änderung

bash

# 1. Backup der aktuellen Config
cp /etc/apache2/sites-enabled/000-website-dergagi-443.conf \
   /root/000-website-dergagi-443.conf.backup-$(date +%Y%m%d-%H%M%S)

# 2. Änderung vornehmen

# 3. Config testen
apache2ctl configtest

# 4. Bei Erfolg: RESTART (nicht reload)
systemctl restart apache2

# 5. Dienste testen
curl -k https://dergagi.changeip.org/yt4k/
curl -k https://dergagi.changeip.org/w/

12.2 Neuen Dienst über Apache proxyen

  1. Dienst starten und Port prüfen:

bash

systemctl start new-service
ss -tlnp | grep :PORT
curl http://127.0.0.1:PORT/
  1. ProxyPass in BEIDEN VirtualHosts hinzufügen:

bash

nano /etc/apache2/sites-enabled/000-catchall-443.conf
# Füge hinzu:
ProxyPass        /newservice/ http://127.0.0.1:PORT/ retry=0
ProxyPassReverse /newservice/ http://127.0.0.1:PORT/

nano /etc/apache2/sites-enabled/000-website-dergagi-443.conf
# Gleiche Zeilen hinzufügen
  1. Testen und Restart:

bash

apache2ctl configtest
systemctl restart apache2
curl -k https://dergagi.changeip.org/newservice/
  1. NICHT in conf-enabled anlegen!

12.3 Docker Container hinzufügen

  1. docker-compose.yml erstellen:

yaml

services:
  newservice:
    image: newservice:latest
    container_name: newservice
    restart: unless-stopped
    ports:
      - "PORT:INTERNAL_PORT"
    volumes:
      - ./data:/data
    networks:
      - newservice_net

networks:
  newservice_net:
    driver: bridge
  1. Starten:

bash

cd /srv/newservice
docker compose up -d
  1. Logs prüfen:

bash

docker logs newservice -f

12.4 SSL-Zertifikat erneuern (Apache)

bash

# Certbot Dry-Run
certbot renew --dry-run

# Manuelle Erneuerung
certbot renew

# Apache neu laden
systemctl reload apache2

# Zertifikat prüfen
openssl x509 -in /etc/letsencrypt/live/dergagi.changeip.org/fullchain.pem -noout -dates

12.5 Monatliche Wartung

bash

# 1. System Updates
apt update && apt upgrade -y

# 2. Docker Images aktualisieren
cd /srv/nextcloud && docker compose pull && docker compose up -d
cd /srv/mediawiki-clean-final && docker compose pull && docker compose up -d

# 3. Alte Docker Images entfernen
docker image prune -a

# 4. Logs rotieren
journalctl --vacuum-time=30d

# 5. Backup prüfen
ls -lh /mnt/nvme_backup/

# 6. RAID Status
cat /proc/mdstat

13. DATEI-PFADE REFERENZ

13.1 Apache

/etc/apache2/sites-available/     Alle verfügbaren Configs
/etc/apache2/sites-enabled/       Aktive Configs (Symlinks)
/etc/apache2/conf-available/      Zusätzliche Configs (sollte leer sein!)
/etc/apache2/conf-enabled/        Aktive zusätzliche Configs
/var/log/apache2/error.log        Error Log
/var/log/apache2/access.log       Access Log
/etc/letsencrypt/live/            SSL-Zertifikate

13.2 Docker

/srv/nextcloud/                   Nextcloud + Traefik
/srv/mediawiki-clean-final/       MediaWiki
/srv/koel/                        Koel Music
/srv/ombi/                        Ombi
/srv/portainer/                   Portainer
/opt/uptime-kuma/                 Uptime Kuma

13.3 SystemD Services

/etc/systemd/system/yt4k.service          YT4K Service
/etc/systemd/system/yt4k.service.d/       YT4K Overrides
/srv/yt4k/                                YT4K Code + venv

/etc/systemd/system/n8n.service           n8n Service
/opt/n8n/                                 n8n Daten

/etc/systemd/system/heatmap8020.service   Heatmap Service
/opt/heatmap8020/                         Heatmap Code + venv

/usr/lib/systemd/system/emby-server.service  Emby Service (System)
/etc/systemd/system/emby-server.service.d/   Emby Overrides
/opt/emby-server/                            Emby Binary
/var/lib/emby/                               Emby Daten

13.4 Backups & Archive

/mnt/nvme_backup/                        System Backups (21 Versionen)
/root/apache-archive-YYYYMMDD-HHMMSS/    Alte Apache Configs
/root/apache-backup-YYYYMMDD-HHMMSS/     Apache Config Backups
/root/network-fix-YYYYMMDD-HHMMSS/       Troubleshooting Logs
/root/apache-old-backups/                Archivierte Backups

14. NÄCHSTE SCHRITTE & EMPFEHLUNGEN

14.1 Kurzfristig (nächste Woche)

  1. Alte Docker-Verzeichnisse aufräumen:

bash

# Prüfen und löschen (wenn nicht mehr benötigt):
/srv/nextcloud-damaged-2025-09-03-112720
/srv/traefik-damaged-2025-09-03-113532
/srv/mw-docker.final-removal.20250831-111413
/opt/n8n.bak.2025-08-23-191443
  1. Apache Archive aufräumen:

bash

# Nach 1 Woche ohne Probleme:
rm -rf /root/apache-archive-20251001-231820
  1. Uptime Kuma Monitoring vervollständigen:
    • Alle Dienste als Monitors hinzufügen
    • E-Mail Alerts konfigurieren

14.2 Mittelfristig (nächster Monat)

  1. HSTS für Port 443 aktivieren:
    • Nachdem Browser-Cache gelöscht ist
    • Nur für / Path, nicht global
    • max-age=15552000 (6 Monate)
  2. Traefik für mehr Dienste nutzen:
    • YT4K, Ombi, MediaWiki könnten über Traefik laufen
    • Vereinfacht SSL-Management
    • Automatische Let's Encrypt Erneuerung
  3. 000-catchall-443.conf entfernen:
    • Alle Requests sollten explizit auf 000-website-dergagi-443.conf matchen
    • Vereinfacht Konfiguration

14.3 Langfristig (optional)

  1. Alle Docker Compose in ein zentrales File:
    • /srv/docker-stack/docker-compose.yml
    • Vereinfacht Management
    • Einheitliche Netzwerk-Struktur
  2. Monitoring erweitern:
    • Prometheus für alle Dienste
    • Alertmanager für Benachrichtigungen
    • Längere Metriken-Retention
  3. Backup-Strategie für Docker Volumes:
    • Automatische Backups für Nextcloud-Daten
    • MediaWiki-Datenbank Dumps
    • Offsite-Backup erwägen

ANHANG A: SCHNELLREFERENZ

Apache Befehle

bash

apache2ctl configtest           # Config testen
apache2ctl -S                   # VirtualHosts anzeigen
apache2ctl -M                   # Module anzeigen
systemctl restart apache2       # Komplett neu starten
systemctl reload apache2        # Config neu laden (unsicher!)
a2ensite site.conf             # Site aktivieren
a2dissite site.conf            # Site deaktivieren
a2enmod proxy_http             # Modul aktivieren

Docker Befehle

bash

docker ps                       # Laufende Container
docker ps -a                    # Alle Container
docker logs CONTAINER           # Logs anzeigen
docker logs -f CONTAINER        # Logs live
docker restart CONTAINER        # Container neu starten
docker compose up -d            # Services starten
docker compose down             # Services stoppen
docker compose restart          # Services neu starten
docker network ls               # Netzwerke anzeigen
docker inspect CONTAINER        # Details anzeigen

SystemD Befehle

bash

systemctl status SERVICE        # Status prüfen
systemctl start SERVICE         # Service starten
systemctl stop SERVICE          # Service stoppen
systemctl restart SERVICE       # Service neu starten
systemctl cat SERVICE           # Config anzeigen (inkl. Overrides)
journalctl -u SERVICE -f        # Logs live
journalctl -u SERVICE -n 50     # Letzte 50 Zeilen

Netzwerk Debug

bash

ss -tlnp                        # Alle lauschenden Ports
ss -tlnp | grep :PORT           # Spezifischer Port
curl http://127.0.0.1:PORT/     # Backend direkt testen
curl -I -k https://domain.com   # Headers anzeigen
netstat -tupln                  # Alternative zu ss

Ende der Dokumentation

Letzte Aktualisierung: 01.10.2025, 23:30 CEST

Version: 1.0

Erstellt von: Claude (Anthropic) mit Daniel Gareis

Archiviert: /mnt/user-data/outputs/STORE2-Network-Architecture-v1.0.md

NVMe-Backup & Datenbank-Backup System - Vollständige Dokumentation v3.0

System-Übersicht

Server: STORE2 (Debian 13)

Backup-Strategien:

  1. OS-Level Backup: Vollständiges System-Backup via rsync + Hard Links
  2. Datenbank-Backup: Zwei-Schicht-Strategie für Calibre/CWA SQLite-Datenbanken

Teil 1: NVMe-Backup System (OS-Level)

Grundlegende Eigenschaften

  • Zweck: Tägliche vollständige OS-Level Disaster Recovery Backups
  • Methode: rsync mit Hard Link Deduplication und --one-file-system
  • Backup-Größe: ~130GB pro Generation (apparent), ~37GB real durch Hard Links
  • Retention: 21 Tage (daily.0 bis daily.20)
  • Zeitplan: Täglich um 03:05 Uhr (±5min Randomisierung)

Hardware-Konfiguration

  • Quelle: NVMe System-Laufwerk (/)
  • Ziel: /mnt/nvme_backup - 1TB HDD (/dev/sdar1, ext4, Label: NVME_BACKUP)
  • Kapazität: 21 Backup-Generationen bei ~85% HDD-Auslastung (geschätzt 777GB)

Funktionsweise der Deduplication

  1. Erste Generation (daily.0): Vollständiges Backup (~130GB apparent)
  2. Folge-Generationen: Nur geänderte/neue Dateien verbrauchen Speicherplatz
  3. Unveränderte Dateien: Hard Links zur vorherigen Generation (0 Byte zusätzlich)
  4. Gemessene Effizienz: 98-99% aller Dateien sind Hard-Linked zwischen Generationen

Realistische Speichernutzung

daily.0: 130G apparent / 7.4GB real (neueste Generation)
daily.1: 126G apparent / 85.5GB real (1 Tag alt)
daily.2: 126G apparent / 4.1GB real (2 Tage alt)

Durchschnitt: ~37GB real pro Generation

21 Generationen: ~777GB total (statt 2.7TB bei Vollbackups)

Pseudo-Inkrementelles System

  • Jede Generation erscheint als vollständiges Filesystem (130GB)
  • Tatsächlicher Speicherverbrauch nur für Änderungen
  • Wiederherstellung jeder Generation als komplettes System möglich
  • Keine Abhängigkeiten zwischen Generationen (jede ist vollständig)

KRITISCH: Verzeichnis-Timestamps verstehen

WICHTIG: Die Timestamps der daily.* Verzeichnisse sind NICHT die Backup-Zeiten!

Warum alle Verzeichnisse das gleiche Datum zeigen:

  • mv innerhalb desselben Filesystems ändert KEINE Directory-mtimes
  • Das Skript macht: mv daily.0 daily.1, mv daily.1 daily.2, etc.
  • Die Directory-Timestamps bleiben beim ersten Erstellen eingefroren

Wo sind die ECHTEN Backup-Zeiten?

  1. Log-Dateien: /mnt/nvme_backup/_logs/run-YYYY-MM-DD_HH-MM-SS.log
  2. Datei-mtimes: Dateien INNERHALB der Backups haben korrekte mtimes
  3. SystemD Journal: journalctl -u nvme-backup.service

Backup-Alter prüfen:

bash

ls -lth /mnt/nvme_backup/_logs/ | head

Software-Komponenten

SystemD Services

  • Service: nvme-backup.service - OneShot-Service für Backup-Ausführung
  • Timer: nvme-backup.timer - Tägliche Ausführung um 03:05 Uhr (±5min)
  • Mail-Services:
    • nvme-backup-mail@success.service - Erfolgs-Benachrichtigung
    • nvme-backup-mail@failure.service - Fehler-Alarm

Scripts und Pfade

  • Backup-Script: /usr/local/sbin/nvme-backup (KEEP=21)
  • Mail-Script: /usr/local/sbin/nvme-backup-mailer
  • Log-Verzeichnis: /mnt/nvme_backup/_logs/
  • Backup-Verzeichnisse: /mnt/nvme_backup/daily.0 bis daily.20

Backup-Ablauf im Detail

Phase 1: Rotation (1-15 Minuten)

Das Skript rotiert die Verzeichnisse rückwärts:

  1. Lösche daily.21 (falls vorhanden) - rm -rf dauert lange!
  2. Verschiebe daily.20daily.21
  3. Verschiebe daily.19daily.20
  4. ... bis daily.0daily.1
  5. Erstelle leeres daily.0

WICHTIG: Das Löschen von daily.21 kann 5-15 Minuten dauern (~49GB Hard-Links). Der Prozess "rm" erscheint in top mit hoher CPU-Last - das ist NORMAL!

Phase 2: rsync (15-60 Minuten)

rsync kopiert von / nach daily.0 mit:

  • --link-dest=daily.1 (Hard Links für unveränderte Dateien)
  • --delete (entfernt gelöschte Dateien aus daily.0)
  • --one-file-system (ignoriert /data, /data2)
  • Fortschritt: Im Log /mnt/nvme_backup/_logs/run-*.log

Phase 3: Fertigstellung

Script loggt "Backup OK" und beendet sich mit Exit 0.

rsync-Parameter

Vollständiger Befehl:

bash

rsync -aAXH --delete --numeric-ids --info=progress2 --one-file-system \
  --link-dest=daily.1 / /mnt/nvme_backup/daily.0

Kritische Parameter:

  • -a: Archive-Mode (rlptgoD) - Permissions, Timestamps, etc.
  • -A: ACLs preservieren
  • -X: Extended Attributes preservieren
  • -H: Hard Links im Quell-System preservieren
  • --delete: Gelöschte Dateien auch aus Backup entfernen
  • --numeric-ids: UIDs/GIDs als Zahlen (nicht Namen)
  • --one-file-system: KRITISCH! Verhindert Backup der RAID-Mounts
  • --link-dest: Hard Links zu daily.1 für unveränderte Dateien

Exclude-Liste

Das Skript schließt folgende Pfade aus:

  • /proc/ - Kernel-Prozess-Dateisystem
  • /sys/ - Kernel-System-Dateisystem
  • /dev/ - Device-Dateien
  • /run/ - Runtime-Daten
  • /tmp/ - Temporäre Dateien
  • /data/ - RAID-Mount md125 (XFS, 52TB)
  • /data2/ - RAID-Mount md126 (EXT4, 61TB)
  • /lost+found - Dateisystem-Recovery
  • /mnt/nvme_backup/* - Backup-Ziel selbst

Backup-Inhalt

Vollständig gesichert:

  • /usr (21GB) - System-Binaries
  • /etc (399MB) - Konfigurationen
  • /boot (417MB) - Kernel, Bootloader
  • /var (42GB) - Docker-Container, Emby-Metadaten, Systemlogs
  • /home (10.5GB) - User-Daten
  • /srv (9.5GB) - Service-Daten (Docker-Compose-Projekte)
  • /opt (1.5GB) - Zusatz-Software
  • /root (20GB) - Admin-Scripts und Configs

KRITISCH: rsync Exitcode 24

Problem: rsync gibt Exitcode 24 zurück, wenn Dateien während des Backups verschwinden.

Ursachen (normal bei Live-Systemen):

  • Docker-Container schreiben/löschen Log-Dateien
  • Browser-Caches werden geleert
  • Temporäre Dateien verschwinden
  • Log-Rotation läuft parallel

Lösung (seit 2025-10-11 implementiert): Exit-Codes 0, 23, 24 werden als Erfolg gewertet. Andere Exit-Codes lösen Fehler-Mail aus.

Tolerierte Exit-Codes:

  • 0: Perfekter Durchlauf
  • 23: Partial transfer (z.B. Permission-Probleme bei einzelnen Dateien)
  • 24: Some files vanished (normale Live-System-Situation)

Mail-Benachrichtigungen

SMTP-Konfiguration

  • Provider: GMX (mail.gmx.net:587, TLS)
  • Absender: dergagi@gmx.de
  • Empfänger: daniel.gareis@gmail.com
  • Auth: /etc/msmtprc (chmod 600)

Mail-Inhalt bei Erfolg

  • Backup-Statistiken (apparent/real size, übertragene Datenmenge)
  • Speicherplatz-Metriken (belegt/verfügbar/Prozent)
  • Retention-Info (Anzahl Generationen, geschätzte Kapazität)
  • System-Status (nächster Backup-Termin, RAID-Status)
  • Performance-Daten (Log-Größe, Dauer)

Mail-Inhalt bei Fehler

  • Error-Details aus journalctl
  • Backup-Festplatten-Status
  • Log-Pfad für weitere Diagnose
  • RAID-Status

Teil 2: Datenbank-Backup System (SQLite)

Übersicht

Zweck: Zwei-Schicht-Backup-Strategie für Calibre/Calibre-Web Datenbanken

Problem: /data wird via --one-file-system vom OS-Backup ausgeschlossen

Lösung: Separate DB-Backups mit unterschiedlichen Retention-Zeiten

Warum separates DB-Backup?

Hintergrund:

  • Calibre-Bibliothek liegt auf /data/ebooks/ (257GB E-Books + 50MB metadata.db)
  • Calibre-Web Config liegt auf /data/ebooks-config/ (87GB Caches + 5MB app.db)
  • /data ist ein separates RAID6-Array (52TB) und wird vom NVMe-Backup ausgeschlossen

Backup-Strategie:

  • E-Books selbst: NICHT gebackupt (257GB, zu groß, regenerierbar aus Quellen)
  • Datenbanken: KRITISCH für Recovery, nur ~70MB
  • Best Practice: SQLite-DBs benötigen konsistente Backups via sqlite3 .backup

Zwei-Schicht-Architektur

Layer 1: Daily Safety Backup (NVMe)

Zweck: Schnelles Recovery bei CWA-Problemen oder Fehlkonfiguration

Eigenschaften:

  • Ziel: /mnt/nvme_backup/_data_dbs/
  • Retention: 7 Tage (tägliche Ordner: YYYY-MM-DD)
  • Zeitplan: Täglich um 03:30 Uhr (nach Haupt-Backup)
  • Größe: ~70MB pro Backup
  • Service: daily-db-backup.service + daily-db-backup.timer

Gebackupte Dateien:

  • calibre_metadata - /data/ebooks/metadata.db (50MB)
  • calibre_prefs - /data/ebooks/metadata_db_prefs_backup.json (16KB)
  • cwa_app - /data/ebooks-config/app.db (5MB)
  • cwa_main - /data/ebooks-config/cwa.db (15MB)

Backup-Methode:

  • SQLite-DBs: sqlite3 $src ".backup $dest" + Integrity-Check
  • JSON-Dateien: Simple cp -p

Layer 2: Weekly Archive Backup (RAID→RAID)

Zweck: Langzeit-Absicherung gegen Hardware-Fehler, tiefere Historie

Eigenschaften:

  • Ziel: /data2/db-archive/
  • Retention: 4 Wochen (Ordner: YYYY-Wxx)
  • Zeitplan: Sonntag 04:00 Uhr
  • Größe: ~103MB pro Archiv (inkl. Backups + Logs)
  • Service: weekly-archive-backup.service + weekly-archive-backup.timer

Gebackupte Dateien (erweitert):

  • Alle aus Daily Backup PLUS:
  • calibre_metadata_backup - /data/ebooks/metadata.db.backup-* (Wildcard)
  • cwa_app_backup - /data/ebooks-config/app.db.backup-* (Wildcard)
  • cwa_logs - /data/ebooks-config/calibre-web.log* (Diagnose)

Vorteile:

  • RAID-zu-RAID: Besserer Hardware-Schutz als NVMe→HDD
  • Wildcard-Gruppen: Automatisches Backup aller DB-Versionen
  • Wöchentlich: Weniger Overhead, längere Geschichte

Software-Komponenten

SystemD Services (Daily Backup)

  • Service: daily-db-backup.service
  • Timer: daily-db-backup.timer (03:30 Uhr täglich)
  • Script: /usr/local/sbin/daily-db-backup
  • Logs: /mnt/nvme_backup/_data_dbs/_logs/

SystemD Services (Weekly Backup)

  • Service: weekly-archive-backup.service
  • Timer: weekly-archive-backup.timer (Sonntag 04:00 Uhr)
  • Script: /usr/local/sbin/weekly-archive-backup
  • Logs: /data2/db-archive/_logs/

Backup-Ablauf

Daily Backup (03:30 Uhr)

  1. Backup-Ordner erstellen: /mnt/nvme_backup/_data_dbs/YYYY-MM-DD/
  2. Für jede Datenbank:
    • SQLite: sqlite3 .backup + PRAGMA integrity_check
    • JSON: cp -p mit Timestamp-Erhalt
  3. Retention: Löscht Backups älter als 7 Tage
  4. Log: Schreibt detailliertes Log nach _logs/

Weekly Backup (Sonntag 04:00 Uhr)

  1. Archiv-Ordner erstellen: /data2/db-archive/YYYY-Wxx/
  2. Haupt-DBs backupen (wie Daily)
  3. Wildcard-Gruppen backupen:
    • Sucht alle *.db.backup-* Dateien
    • Kopiert in Unterordner
  4. Logs archivieren: Alle calibre-web.log* für Diagnose
  5. Retention: Löscht Archive älter als 4 Wochen
  6. Speicherplatz-Check: Zeigt /data2 Belegung

Wichtige Unterschiede zu OS-Backup

Service-Kontrolle

Status prüfen

bash

# Daily Backup
systemctl status daily-db-backup.timer
systemctl status daily-db-backup.service
ls -lth /mnt/nvme_backup/_data_dbs/_logs/ | head

# Weekly Backup
systemctl status weekly-archive-backup.timer
systemctl status weekly-archive-backup.service
ls -lth /data2/db-archive/_logs/ | head

Manueller Start

bash

# Daily Backup manuell ausführen
systemctl start daily-db-backup.service

# Weekly Backup manuell ausführen
systemctl start weekly-archive-backup.service

Backup-Struktur anzeigen

bash

# Daily Backups (letzte 7)
ls -lh /mnt/nvme_backup/_data_dbs/

# Weekly Archive (letzte 4)
ls -lh /data2/db-archive/

# Detaillierter Inhalt eines Backups
tree /mnt/nvme_backup/_data_dbs/2025-10-11/

Teil 3: Wartung und Troubleshooting

NVMe-Backup Troubleshooting

Problem 1: Service schlägt fehl mit Exit 24

Symptom: Mail "NVMe Backup FEHLGESCHLAGEN", journalctl zeigt "rsync warning: some files vanished"

Ursache: Normale Live-System-Situation

Lösung: Seit 2025-10-11 toleriert das Skript Exitcode 24. Bei älteren Skript-Versionen: Neues Skript installieren.

Problem 2: Backup-Disk voll

Symptom: rsync schlägt fehl mit "No space left on device"

Ursache: Mehr als erwartete Änderungen, oder Retention zu hoch

Lösung:

bash

# KEEP von 21 auf 18 oder 15 reduzieren
sed -i 's/KEEP=21/KEEP=18/' /usr/local/sbin/nvme-backup

# Alte Docker-Images aufräumen
docker system prune -a

# Journal bereinigen
journalctl --vacuum-time=30d

Problem 3: Backup dauert sehr lange

Symptom: rm-Prozess läuft 15+ Minuten

Ursache: daily.21 hat sehr viele Dateien (Hard-Links brauchen Zeit zum Löschen)

Lösung: Normal, abwarten. Ext4 braucht Zeit für Millionen Inodes.

Problem 4: Verzeichnis-Timestamps sind alt

Symptom: "daily.0 zeigt 7. Sep, aber heute ist 11. Okt"

Ursache: Normal! mv ändert keine Directory-mtimes

Lösung: Logs anschauen für echte Backup-Zeiten:

bash

ls -lth /mnt/nvme_backup/_logs/

DB-Backup Troubleshooting

Problem 1: SQLite Integrity-Check schlägt fehl

Symptom: Log zeigt "⚠ Integritäts-Check fehlgeschlagen"

Ursache: Korrupte Datenbank im Live-System

Lösung:

bash

# Manuelle Integritätsprüfung
sqlite3 /data/ebooks/metadata.db "PRAGMA integrity_check;"

# Bei Korruption: Von älterem Backup wiederherstellen
cp /mnt/nvme_backup/_data_dbs/2025-10-10/calibre_metadata \
   /data/ebooks/metadata.db.restored

Problem 2: Wildcard-Gruppe findet keine Dateien

Symptom: Log zeigt "⚠ Keine Dateien gefunden"

Ursache: Keine Backup-Dateien vorhanden (z.B. nach CWA-Neuinstallation)

Lösung: Normal, keine Aktion nötig. Das Skript überspringt diese Gruppe.

Problem 3: Backup schlägt mit Exit 1 fehl

Symptom: Service-Status zeigt "failed"

Ursache: Quell-Datenbank nicht gefunden (z.B. Docker-Container gestoppt)

Lösung: Prüfen ob CWA läuft:

bash

docker ps | grep calibre
ls -lh /data/ebooks-config/app.db

Wiederherstellung (Recovery)

Daily Backup Recovery (schnell)

Szenario: CWA-Datenbank nach Update korrupt

bash

# 1. CWA stoppen
docker stop calibre-web

# 2. Backup wiederherstellen (gestern)
cp /mnt/nvme_backup/_data_dbs/2025-10-10/cwa_app \
   /data/ebooks-config/app.db

# 3. Permissions korrigieren
chown gagi:gagi /data/ebooks-config/app.db

# 4. CWA starten
docker start calibre-web

Weekly Archive Recovery (tiefer)

Szenario: Calibre-Bibliothek korrupt, brauche Version von vor 3 Wochen

bash

# 1. Verfügbare Archive anzeigen
ls -lh /data2/db-archive/

# 2. Gewünschte Woche finden (z.B. 2025-W38)
ls -lh /data2/db-archive/2025-W38/

# 3. Backup wiederherstellen
cp /data2/db-archive/2025-W38/calibre_metadata \
   /data/ebooks/metadata.db

# 4. Permissions
chown gagi:gagi /data/ebooks/metadata.db

# 5. Calibre restarten (falls Container läuft)
docker restart calibre

Vollständige System-Wiederherstellung (NVMe)

Szenario: NVMe-SSD versagt komplett

bash

# 1. Neue NVMe-SSD einbauen
# 2. Debian 13 Minimal installieren
# 3. Backup-HDD mounten
mount /dev/sdar1 /mnt/backup

# 4. System wiederherstellen
rsync -aAXH --numeric-ids /mnt/backup/daily.0/ /mnt/newsystem/

# 5. Bootloader neu installieren
chroot /mnt/newsystem
grub-install /dev/nvme0n1
update-grub
exit

# 6. Reboot
reboot

Teil 4: Performance und Kapazität

NVMe-Backup Performance

  • Erstes Backup: ~130GB in 1,5 Stunden (Vollübertragung)
  • Folge-Backups: ~5-40GB in 15-60 Minuten (nur Änderungen)
  • CPU-Verbrauch: ~4 Minuten CPU-Zeit pro Backup
  • Memory Peak: ~5.7GB während Backup
  • Hard Link Effizienz: 98-99% Dateien verlinkt zwischen Generationen
  • Durchschnittlicher Speicherverbrauch: 37GB real pro Generation

Rotation (rm -rf daily.21):

  • Dauer: 5-15 Minuten
  • CPU: 20-30% eines Cores
  • Grund: Millionen Hard-Links müssen aufgelöst werden

DB-Backup Performance

  • Daily Backup: ~3 Sekunden (4 Dateien, 70MB)
  • Weekly Backup: ~5 Sekunden (7 Items, 103MB)
  • CPU-Verbrauch: Minimal (<1% Core)
  • Speicherverbrauch: ~500MB pro Woche

Kapazitäts-Management

NVMe-Backup

  • Aktuelle Nutzung (typisch): 330-400GB für 21 Generationen
  • Projektion 21 Tage: ~777GB (85% der 916GB HDD)
  • Sicherheitspuffer: ~140GB für Variabilität
  • Überwachung: Automatisch via Mail nach jedem Backup

DB-Backups

  • Daily (NVMe): 7 × 70MB = ~490MB
  • Weekly (RAID): 4 × 103MB = ~412MB
  • Total: <1GB für beide Backup-Layer

Notfall-Maßnahmen bei Speicherknappheit (NVMe-Backup):

Option 1: Retention reduzieren

bash

sed -i 's/KEEP=21/KEEP=18/' /usr/local/sbin/nvme-backup

Option 2: System-Dateien aufräumen

bash

docker system prune -a
journalctl --vacuum-time=30d
apt clean && apt autoclean

Option 3: Manuelle Backup-Löschung

bash

rm -rf /mnt/nvme_backup/daily.20
rm -rf /mnt/nvme_backup/daily.19

Teil 5: Integration in Gesamtsystem

Drei-Schicht-Backup-Architektur

Layer 1: RAID6-Arrays (Live-Redundanz)

  • /data (md125, XFS, 52TB) - E-Books, Medien
  • /data2 (md126, EXT4, 61TB) - Backups, Archive
  • Zweck: Hardware-Redundanz gegen Festplattenausfall

Layer 2: NVMe-Backup (System-Recovery)

  • Ziel: /mnt/nvme_backup (1TB HDD)
  • Retention: 21 Tage
  • Zweck: Vollständige OS-Wiederherstellung, 3-Wochen-Historie

Layer 3: DB-Backups (Datenbank-Schutz)

  • Daily: /mnt/nvme_backup/_data_dbs/ (7 Tage)
  • Weekly: /data2/db-archive/ (4 Wochen)
  • Zweck: SQLite-konsistente Backups für Calibre/CWA

Optimierte Ressourcen-Aufteilung

  • RAID-Schutz: 113TB Nutzdaten mit Hardware-Redundanz
  • NVMe-Backup: 130GB System-Recovery mit 3-Wochen-Historie
  • DB-Backups: <1GB für 7+28 Tage Datenbank-Historie
  • Hard Link Effizienz: 777GB für 21 Vollbackups (statt 2.7TB)

Zeitplan-Koordination

03:05 Uhr: NVMe-Backup (OS-Level) startet
03:30 Uhr: Daily DB-Backup startet (nach OS-Backup)
04:00 Uhr: Weekly Archive-Backup (nur Sonntag)

Grund: DB-Backups laufen NACH dem Haupt-Backup, um Konflikte zu vermeiden.


Changelog

v3.0 (2025-10-11):

  • Zwei-Schicht-DB-Backup-System hinzugefügt
  • Daily Safety Backup (NVMe, 7 Tage)
  • Weekly Archive Backup (RAID→RAID, 4 Wochen)
  • SQLite .backup API für konsistente DB-Kopien
  • Separate SystemD Services/Timers für DB-Backups
  • Dokumentation komplett überarbeitet und erweitert

v2.0 (2025-10-11):

  • Exit-Code-24-Toleranz hinzugefügt (Exit 0/23/24 = Erfolg)
  • Dokumentation zu Directory-Timestamps ergänzt
  • Troubleshooting-Sektion erweitert
  • Performance-Charakteristika gemessen und dokumentiert

v1.0 (2025-09-07):

  • Initiale 21-Tage-Retention
  • Mail-Benachrichtigungen implementiert
  • Hard-Link-Backup produktiv

Ende der Dokumentation v3.0

STORE2 NVME Disaster Recovery Dokumentation

Übersicht

Diese Dokumentation beschreibt die vollständige Wiederherstellung des STORE2-Servers nach einem totalen NVMe-SSD-Ausfall. Das Verfahren basiert auf täglichen rsync-Backups mit Hard-Link-Deduplication.

Systemdaten:

  • Backup-System: rsync mit --link-dest (21 Generationen)
  • Backup-Größe: ~118GB pro Generation
  • Recovery-Zeit: 4-5 Stunden gesamt
  • Besonderheit: RAID-Arrays sind mit LUKS verschlüsselt!

Voraussetzungen

Hardware-Anforderungen

  • Neue NVMe SSD (Minimum: 256GB, Empfohlen: 512GB, Optimal: 1TB)
  • Debian 13 Live-USB oder Installations-Medium
  • Physischer Zugriff auf STORE2
  • Monitor und Tastatur
  • Netzwerkkabel für spätere Updates

Kritische Systeminformationen (STORE2 Stand: September 2025)

System-Partitionierung:

  • /dev/nvme0n1p1: 222,6GB ext4 (Root-Partition)
  • /dev/nvme0n1p5: 15,9GB swap
  • Root-UUID: 0bcdb676-123c-4658-925e-9cba9ecf45df

Backup-HDD:

  • Device: /dev/sdar1
  • Filesystem: ext4
  • Label: NVME_BACKUP
  • UUID: 1c2b9b3c-f436-404a-9777-aa288477a7a8
  • Mount: /mnt/nvme_backup

RAID-Arrays (VERSCHLÜSSELT mit LUKS!):

  • md125: RAID6, 20 Disks, 52TB, XFS, verschlüsselt
    • LUKS UUID: a54ac812-bb0e-4228-b3f7-2961fbb74ce7
    • Decrypted: /dev/mapper/cr_md125
    • Filesystem UUID: 9787dc50-bdd5-4054-901c-bf4657db7ab4
    • Mount: /data
  • md126: RAID6, 23 Disks, 61TB, EXT4, verschlüsselt
    • LUKS UUID: 82d138cd-958d-42bc-b0f2-08eaa06f447d
    • Decrypted: /dev/mapper/cr_md126
    • Filesystem UUID: 72ee2927-2855-4ebd-a7d0-3d8f4a3450c1
    • Mount: /data2

Netzwerk:

  • Interface: enp0s31f6 (NICHT eth0!)
  • MAC: 30:9c:23:68:bf:e8
  • Hostname: STORE2
  • Domain: dergagi.changeip.org

Phase 1: Vorbereitung (30 Minuten)

1.1 Hardware-Vorbereitung

  1. Server herunterfahren: shutdown -h now
  2. Stromversorgung trennen
  3. Defekte NVMe entfernen
  4. Neue NVMe einbauen
  5. WICHTIG: Backup-HDD (/dev/sdar1) und RAID-Disks NICHT entfernen!

1.2 Informationen dokumentieren (falls System noch läuft)

Folgende Befehle ausführen und Ausgaben sichern:

lsblk -f > /tmp/lsblk-output.txt blkid > /tmp/blkid-output.txt ip link show > /tmp/network-interfaces.txt cat /proc/mdstat > /tmp/raid-status.txt cat /etc/fstab > /tmp/fstab-backup.txt cat /etc/crypttab > /tmp/crypttab-backup.txt

Diese Dateien auf USB-Stick oder per Mail sichern!

Phase 2: Basis-Installation (45 Minuten)

2.1 Debian 13 installieren

  1. Von Debian 13 USB/DVD booten
  2. Installationstyp: Minimal (ohne Desktop-Umgebung)
  3. Partitionierung EXAKT wie Original:
    • /dev/nvme0n1p1: 223GB ext4 für /
    • /dev/nvme0n1p5: 16GB swap
  4. Hostname: STORE2 (wichtig!)
  5. Root-Passwort: Temporär (wird überschrieben)
  6. Netzwerk: NICHT konfigurieren
  7. Software: Nur "Standard-Systemwerkzeuge"

2.2 Nach Installation

  • System einmal booten lassen
  • Als root anmelden
  • Herunterfahren: shutdown -h now

Phase 3: Recovery via Live-System (2-3 Stunden)

3.1 Live-System vorbereiten

  1. Von Debian Live-USB booten
  2. Terminal öffnen
  3. Root werden: sudo -i

3.2 Partitionen identifizieren

lsblk -f

Backup-HDD finden (Label: NVME_BACKUP)

blkid | grep NVME_BACKUP

Sollte zeigen: /dev/sdar1

Neue NVMe-Root finden

blkid | grep nvme0n1p1

NEUE UUID notieren!

3.3 Partitionen mounten

mkdir -p /mnt/new-system mkdir -p /mnt/backup

Neue NVMe mounten

mount /dev/nvme0n1p1 /mnt/new-system

Backup-HDD mounten (normalerweise sdar1)

mount /dev/sdar1 /mnt/backup

Prüfen

df -h | grep mnt

3.4 System wiederherstellen

WICHTIG: Dieser Schritt dauert 2-3 Stunden!

rsync -aAXHv --info=progress2

--exclude='/proc/'

--exclude='/sys/'

--exclude='/dev/'

--exclude='/run/'

--exclude='/tmp/'

--exclude='/mnt/'

/mnt/backup/daily.0/ /mnt/new-system/

Erwartete Werte:

  • Dateien: ~1.7 Millionen
  • Daten: ~118GB
  • Dauer: 2-3 Stunden

Phase 4: System-Anpassung (1 Stunde)

4.1 Chroot vorbereiten

KRITISCH: Exakte Reihenfolge beachten!

mkdir -p /mnt/new-system/{dev,proc,sys,run}

mount --bind /dev /mnt/new-system/dev mount --bind /proc /mnt/new-system/proc mount --bind /sys /mnt/new-system/sys mount --bind /run /mnt/new-system/run mount --bind /dev/pts /mnt/new-system/dev/pts

chroot /mnt/new-system /bin/bash

Test ob chroot funktioniert

ls /root cat /etc/hostname # Sollte "STORE2" zeigen

4.2 Hardware-Anpassungen

UUID in /etc/fstab anpassen:

Neue UUID ermitteln

blkid | grep nvme0n1p1

Beispiel: UUID="neue-uuid-hier"

Backup

cp /etc/fstab /etc/fstab.backup

fstab editieren

nano /etc/fstab

ÄNDERN:

ALT: UUID=0bcdb676-123c-4658-925e-9cba9ecf45df / ext4 ...

NEU: UUID=NEUE-UUID-HIER / ext4 ...

Syntax prüfen

mount -a

Sollte keine Fehler zeigen (Warnungen OK)

GRUB neu installieren:

grub-install /dev/nvme0n1

Sollte zeigen:

Installing for x86_64-efi platform.

Installation finished. No error reported.

update-grub

Sollte Kernel finden und grub.cfg generieren

Initramfs neu bauen:

update-initramfs -u -k all

4.3 Netzwerk anpassen

Interface-Namen prüfen

ip link show

/etc/network/interfaces editieren

nano /etc/network/interfaces

Falls Interface-Name anders (meist enp0s31f6 statt eth0):

allow-hotplug enp0s31f6

iface enp0s31f6 inet dhcp

4.4 Chroot verlassen und unmounten

exit

Unmount in UMGEKEHRTER Reihenfolge!

umount /mnt/new-system/dev/pts umount /mnt/new-system/run umount /mnt/new-system/sys umount /mnt/new-system/proc umount /mnt/new-system/dev umount /mnt/new-system umount /mnt/backup

reboot

Phase 5: Post-Recovery (30 Minuten)

5.1 Erster Boot

Nach dem Boot als root einloggen:

Netzwerk prüfen

ip a ping -c 3 8.8.8.8

Falls kein Netzwerk:

systemctl restart networking

SSH aktivieren

systemctl start ssh systemctl enable ssh

5.2 RAID-Arrays wiederherstellen

WICHTIG: Arrays sind LUKS-verschlüsselt!

Arrays assemblieren:

mdadm --assemble --scan

Status prüfen:

cat /proc/mdstat

Sollte md125 und md126 zeigen

LUKS entsperren (Passwort erforderlich!):

cryptsetup luksOpen /dev/md125 cr_md125 cryptsetup luksOpen /dev/md126 cr_md126

Mounten:

mount /dev/mapper/cr_md125 /data mount /dev/mapper/cr_md126 /data2

Prüfen:

df -h | grep data

Für automatisches Entsperren beim Boot:

/etc/crypttab prüfen/anpassen!

5.3 Docker-Services starten

systemctl status docker

Falls nicht läuft:

systemctl start docker

Container-Status

docker ps -a

Alle Container starten

docker start $(docker ps -aq)

Warten (2-3 Minuten)

docker ps

5.4 Kritische Services prüfen

Apache

systemctl status apache2 curl -k https://localhost/site

Backup-Timer

systemctl status nvme-backup.timer systemctl list-timers | grep backup

Emby

systemctl status emby-server

Alle fehlgeschlagenen Services anzeigen

systemctl list-units --failed

Phase 6: Vollständige Verifikation

6.1 Service-Checkliste

Zu prüfende Services:

6.2 Docker-Container prüfen

Alle Container sollten "Up" sein

docker ps --format "table {{.Names}}\t{{.Status}}"

Logs bei Problemen prüfen

docker logs <container-name>

6.3 RAID-Integrität

RAID-Status detailliert

mdadm --detail /dev/md125 mdadm --detail /dev/md126

Smart-Status der RAID-Disks

smartctl -a /dev/sda | grep -E "SMART overall|Reallocated"

Troubleshooting

Problem: GRUB Error "no such device"

  1. Von Live-USB booten
  2. Chroot-Prozedur wiederholen
  3. UUID in /etc/fstab nochmals prüfen
  4. update-grub erneut ausführen

Problem: Netzwerk funktioniert nicht

ip link show

Interface-Name notieren (z.B. enp0s31f6)

nano /etc/network/interfaces

Interface-Namen anpassen

systemctl restart networking

Problem: RAID-Arrays werden nicht entschlüsselt

Prüfen ob Arrays da sind

cat /proc/mdstat

Manuell entsperren

cryptsetup luksOpen /dev/md125 cr_md125 cryptsetup luksOpen /dev/md126 cr_md126

/etc/crypttab prüfen

cat /etc/crypttab

Sollte beide Arrays enthalten

Problem: Docker-Container starten nicht

systemctl restart docker docker start <container-name> docker logs <container-name>

Zeitplan

Kritische Hinweise

RAID-Verschlüsselung: Die RAID-Arrays md125 und md126 sind mit LUKS verschlüsselt! Das Entschlüsselungs-Passwort wird benötigt. Ohne dieses Passwort sind die 113TB Daten nicht zugänglich.

Interface-Namen: Das Netzwerk-Interface heißt enp0s31f6, NICHT eth0. Dies muss in /etc/network/interfaces angepasst werden.

Docker-Volumes: Alle im Backup enthalten unter /var/lib/docker/volumes/

Backup-HDD: Device /dev/sdar1 mit Label NVME_BACKUP - NIEMALS formatieren!

IP-Adressen: Bei MAC-Änderung könnte DHCP neue IP vergeben.

Notfall-Kontakte

  • Zugriff via Live-System immer möglich
  • Backup-HDD (/dev/sdar1) ist die Lebensversicherung
  • RAID-LUKS-Passwort sicher aufbewahrt?
  • Logs in /var/log/ und /root/chatgpt-logs/

Nach erfolgreicher Recovery

Backup-System prüfen:

Backup-Timer prüfen

systemctl status nvme-backup.timer systemctl list-timers | grep nvme

Test-Backup

systemctl start nvme-backup.service

Log beobachten

tail -f /mnt/nvme_backup/_logs/run-*.log

HDD als NTFS unter Linux richtig formatieren

Szenario: Raid-Platte geht noch, liefert aber sporadische Fehler in dmesg z.B. -> wird im Raid ersetzt -> ist dann "über" -> kann als Serien-Sammelplatte noch verwendet werden

Damit die Platte auch unter Windows richtig erkannt wird ist folgendes zu beachten:

Partitionstyp muss auf 0x07 (HPFS/NTFS/exFAT) stehen!

Partitionieren mit gdisk

sudo gdisk /dev/sdX
  • erst alte Linux Raid Partiton löschen: d -> 1 -> w
  • n → Neue Partition anlegen (Eingaben bestätigen oder (falls gewünscht) Start- und Endsektor anpassen)
  • 0700 als Typ für NTFS setzen (wird ggf. vorgeschlagen, sonst nachfragen)
  • w → Schreiben und gdisk verlassen

Formatieren mit mkfs.ntfs

sudo mkfs.ntfs -f /dev/sdX1

Mounten mit

sudo mkdir -p /mnt/ntfs
sudo mount -t ntfs-3g /dev/sdX1 /mnt/ntfs

Booten überhaupt !!!

Bios 12 ist OK. Kerne laufen beide auf 2.5Ghz.

Beide Karten sind OK und müssen auch beim Booten drin sein

Wenn die Laufwerke vom 4-Ch Sata-Controller ab sind, wir auch gebootet.

Dann können sie Hot-Geplugged werden -> geht :-)

Jetzt testen dass auch alle 27 (!) Laufwerke da sind.

/root/bin/diskserial_sort.sh 

Dann weiter wie im Raidabschnitt beschrieben

mdadm --assemble --scan

Raid-Karten Kernel-Treiber nach Kernelupdate

cd /Nach_Kernelupdate/rr2340-linux-src-v1.7/product/rr2340/linux/ 
make clean
make
make install

Manuelles starten (nach Reboot automatisch)

modprobe rr2340

Grub und Root-Festplatte

in /boot/grub/menu.lst z.B.

kernel /boot/vmlinuz-2.6.31.14-0.6-desktop root=UUID=d06e4d6a-44d7-4f09-9ea3-a4cb8f120770 ...

UUID einer Festplatte herausfinden

blkid /dev/sdq8

Screen-Umgebung

http://linuxwiki.de/screen

Liste aller Screens

screen -ls

Starten

screen -S NAME

Detach

Strg-a d = detach

Reatach

screen -r NAME

ODER Wieder reingehen

screen -x NAME 

Screens beenden

im Screen Strg-a k (wie kill)

Arch Linux AUR Pakete

- tarball herunterladen
- nach /builds entpacken (tar -xzf xxxx.tar.gz)
- dort makepkg
- pacman -U xxxx.pkg.tar.xz

RAR unter Linux

RAR-Archiv testen

rar t xxxxx.rar 

Wake-On-Lan

Netzwerkkarte in System->Gerätemanager erlauben und Magic Paket einstellen im Bios PCI aufwecken erlauben Mac-Adresse und Netzwerk-IP wissen

Uni

Linux-Konsolen-Befehl zum Aufwecken auf Uni-Rechner Big-Blue2 aus "Hibernate":

wol -i 132.187.33.255 90:e6:ba:43:c2:dc 

Busfahrer an Uni:

wol -i 132.187.33.255 b8:ac:6f:67:e6:43 

Brücknerstrasse

Aufwecken aus "Standby"

(Bachus)

wol -i 255.255.255.255 00:1e:8c:46:10:8c 

(Myth intern)

wol -i 255.255.255.255 00:14:85:e8:10:4c

Myth PCIe

wol -i 255.255.255.255 00:e0:45:49:00:09

Tool um Windows um Remote-Verbindung schlafen zu legen PowerOff z.B. bei

http://www.chip.de/downloads/Poweroff_21571048.html

Linuxbefehl für OpenSuse um per Konsole zu suspenden:

pm-suspend 

-> Vorsicht: Festplatten verhalten sich komisch

"HDIO_DRIVE_CMD(identify) failed: Invalid exchange" 

bei

 /root/bin/diskserial_sort.sh 

Aufwecken über Fritzbox direkt problemlos möglich.

Remote-Desktop

Big-Blue: SSH auf wolf.physik.uni-wuerzburg.de mit Tunnel: 33889 auf Ziel 132.187.33.133:3389 Dann localhost:33889

Myth: dergagi.dyndns.org normal (ohne Angabe gilt Port 3389)

Bachus: dergagi.dyndns.org:33890

Ordnergröße in Konsole anzeigen

du -sh /home

Für Platzstatus auf Partitionen

df -h

DU-Meter für SuSE/Linux

KTrafficAnalyzer, z.B. über 1-Klick Installation bei http://software.opensuse.org/search

NTM http://netramon.sourceforge.net/eng/index.html

Bandwidth-Monitor für Console, z.B. auch Ubuntu

bwm-ng
bmon

Netzwerk-Geschwindkeit testen

Tool: iperf gibts für Linux, Windows, Mac Server (empfängt Testdaten)

iperf -s

Client (sendet Daten)

iperf -c 192.168.1.60  (Myth)
ipfer -c 192.168.1.66  (Store)

Manuel RPM Pakete installieren

rpm -ihv nedit-5.5-31.8.x86_64.rpm

Locate auf Data/Data2

locate -i -d /data/locatedb "mein suchbegriff"

USB-Device mounten

mount -t ntfs-3g /dev/sdj5 /usb -o force

NTFS Linux

mount -t ntfs-3g /dev/sds1 /mo1

Opensuse: IP über DHCP erneuern

  1.  Open a terminal and su - to root.
  2. Type ifconfig to show the current IP address that you received from DHCP.
  3. Type dhcpcd -k to send the appropriate signals to dhcpcd.
  4. Now bring the interface back up by typing ifup eth0.
  5. Type ifconfig to show the new IP address.

System-Backup-Image von USB-Platte mounten

mount -o loop /media/Data5/store_root.img /mnt/loop/

Verzeichnisse synchronisieren

mit grsync

Devices neu einlesen im laufenden Betrieb ohne Reboot

blockdev --rereadpt /dev/sdx

Laufwerke am RocketRaid neu einlesen im laufenden Betrieb ohne Reboot

Kernelmodul da?

lsmod rr2340

Kernelmodul entfernen/löschen

rmmod rr2340

Kernelmodul wieder laden/starten

modprobe rr2340

KDE Remote Desktop

krdc -> Client

TightVNC -> Client

krfb -> Server (über Konsole z.B. mit Xming starten, wegen Grafik)

Port Forwarding im Router: Kontrolle unter: vi home/root/kde4/share/config/krfbrc

JDownloader

Installieren über Script von Homepage

  1. wget must be installed on system!
  2. Download jd.sh
  http://212.117.163.148/jd.sh
  3. chmod +x jd.sh
  4. start jd.sh -> ./jd.sh

Note: Open jd.sh to read Manual or change Settings!

Starten nach Installation:

java -jar /home/gagi/.jd/JDownloader.jar

One-Click Install auf Konsole

OCICLI <YMP URL>

Cronjobs

Liste

crontab -l

Einträge ändern

crontab -e

dort dann im vi editieren

Data Scrubbing, automatische Suche einmal im Monat nach BadBlocks

In short: Especially if you run a RAID5 array, trigger an active bad block check on a regular basis, or there is a high chance of hidden bad blocks making your RAID unusable during reconstruction.

Normally, RAID passively detects bad blocks. If a read error occurs, the data is reconstructed from the rest of the array, and the bad block is rewritten. If the block can not be rewritten, the defective disk is kicked out of the active array.

Once the defective drive is replaced, reconstruction will cause all blocks of the remaining drives to be read. If this process runs across a previously undetected bad block on the remaining drives, another drive will be marked as failed, making RAID5 unusable. The larger the disks, the higher the odds that passive bad block detection will be inadaquate. Therefore, with today's large disks it is important to actively perform data scrubbing on your array.

With a modern (>=2.6.16) kernel, this command will initiate a data consistency and bad block check, reading all blocks, checking them for consistency, and attempting to rewrite inconsistent blocks and bad blocks.

echo check >> /sys/block/md127/md/sync_action
echo check >> /sys/block/md125/md/sync_action

You can monitor the progress of the check with:

watch -n .1 cat /proc/mdstat

You should have your array checked daily or weekly by adding the appropriate command to /etc/crontab.

Steht für jeden 8. des Monats in Crontab.

If you find yourself needlessly checking your array (like I was) and want to stop it safely, you can either stop the entire array, or:

echo idle >> /sys/block/md127/md/sync_action
echo idle >> /sys/block/md125/md/sync_action

TigerVNC

Start Server

vncserver :1 
vncserver :2 

Kill Server

vncserver -kill :1 

Port 5901

dergagi.selfhost.bz:5901 
dergagi.selfhost.bz:5902 

Auflösung ändern:

im VNC-Fenster (also schon remote)

xrandr -s 1920x1200

XTerm Benutzer wechseln:

su gagi

Autostart

in /etc/rc.local

su gagi -c "vncserver -geometry 1920x1080 -alwaysshared -localhost -dpi 96 :1"

RSYNC volles Systembackup

rsync -aAXv --exclude={"/dev/*","/proc/*","/sys/*","/tmp/*","/run/*","/mnt/*","/media/*","/lost+found","/data","/data2","/suse","/rsync-backup"} / /rsync-backup/