Homelab – Storage & Backup

Storage-Architektur und Backup-Strategie des Proxmox-Hosts. Zurück zum Homelab-Überblick.


Storage

MergerFS-Pool

Drei 2,5-Zoll HDDs via USB am OptiPlex, zusammengefasst mit MergerFS zu einem logischen Pool unter /mnt/storage. USB ist der bekannte Schwachpunkt — Langfristplan ist ein M.2-SATA-Controller (ASM1166, 6 Ports).

MergerFS-Policy: category.create=mfs — neue Dateien landen auf der Disk mit dem meisten freien Platz. Reserved Blocks auf 1% reduziert (tune2fs -m 1). Nutzbare Kapazität: ~13,5 TB.

fstab

UUID=<disk1-uuid>  /mnt/disk1  ext4  defaults,nofail,x-systemd.device-timeout=120  0 2
UUID=<disk2-uuid>  /mnt/disk2  ext4  defaults,nofail,x-systemd.device-timeout=120  0 2
UUID=<disk3-uuid>  /mnt/disk3  ext4  defaults,nofail,x-systemd.device-timeout=120  0 2
/mnt/disk1:/mnt/disk2:/mnt/disk3  /mnt/storage  fuse.mergerfs  defaults,nonempty,x-systemd.requires=mnt-disk1.mount,x-systemd.requires=mnt-disk2.mount,x-systemd.requires=mnt-disk3.mount,x-systemd.after=mnt-disk1.mount,x-systemd.after=mnt-disk2.mount,x-systemd.after=mnt-disk3.mount,allow_other,use_ino,category.create=mfs,fsname=mergerfs,nofail  0 0

Konkrete UUIDs in [[Homelab – Privat]].

MergerFS Boot-Fix

USB-HDDs brauchen beim Boot ein paar Sekunden zum Spin-up. Ohne Fix starten LXCs bevor MergerFS gemountet ist — Services sehen ein leeres Verzeichnis. Drei Maßnahmen:

  1. fstab: x-systemd.device-timeout=120 gibt USB-Disks 120 Sekunden zum Erscheinen
  2. fstab: MergerFS-Eintrag mit x-systemd.requires und x-systemd.after für alle drei Disk-Mounts
  3. systemd Drop-in: pve-guests.service wartet auf mnt-storage.mount bevor LXCs gestartet werden
# /etc/systemd/system/pve-guests.service.d/wait-for-storage.conf
[Unit]
Requires=mnt-storage.mount
After=mnt-storage.mount

Wichtig: Wenn Disks manuell ausgehängt werden (z.B. für SMART-Checks), vorher abhängige LXCs stoppen (pct stop 102 105 106). Nach Remount wieder starten.

Verzeichnisstruktur

/mnt/storage/
├── usenet/
│   ├── incomplete/      SABnzbd (CT 102, rw)
│   └── complete/
│       ├── movies/      SABnzbd → Radarr
│       └── tv/          SABnzbd → Sonarr
├── media/
│   ├── movies/          Radarr (CT 102, rw) | Jellyfin (CT 103, ro)
│   ├── tv/              Sonarr (CT 102, rw) | Jellyfin (CT 103, ro)
│   └── youtube/         Pinchflat (CT 102, rw) | Jellyfin (CT 103, ro)
├── photos/              Immich (CT 105, rw)
├── documents/           Paperless-ngx (CT 106, rw)
└── backup/
    ├── vzdump/          Proxmox vzdump (Host)
    ├── docker-configs/  Config-Backup-Script (Host)
    └── homeassistant/   HA Samba Backup (Pi)

TRaSH-konforme Struktur: Radarr, Sonarr und SABnzbd bekommen alle /mnt/storage als /data gemountet — ein einziges Dateisystem, Hardlinks und Atomic Moves funktionieren.

LXC Bind-Mounts

CTMount auf HostMount in LXCModusHost-UID
102 (servarr)/mnt/storage/mnt/mediarw101000
103 (media)/mnt/storage/dataro
105 (photos)/mnt/storage/photos/mnt/photosrw100000
106 (documents)/mnt/storage/documents/mnt/documentsrw101000

CT 104 hat keinen Storage-Mount — kein Service dort braucht Medienzugriff.


Backup

Ebene 1: LXC-Snapshots (vzdump)

Wöchentlich, Sonntag 03:00. Konfiguriert in der Proxmox Web-UI unter Datacenter → Backup.

EinstellungWert
CompressionZSTD
ModeSnapshot
RetentionKeep Last = 4

Ebene 2: Docker-Config-Backup

Wöchentliches tar der /opt-Verzeichnisse aller LXCs. Script: /root/backup-configs.sh, Cron: Sonntag 04:00.

#!/bin/bash
BACKUP_DIR="/mnt/storage/backup/docker-configs"
DATE=$(date +%Y%m%d)
mkdir -p "$BACKUP_DIR"
 
for CT in 101 102 103 104 105 106; do
  pct exec $CT -- tar czf /tmp/config-backup.tar.gz -C /opt .
  pct pull $CT /tmp/config-backup.tar.gz "$BACKUP_DIR/ct${CT}-${DATE}.tar.gz"
  pct exec $CT -- rm /tmp/config-backup.tar.gz
done
 
find "$BACKUP_DIR" -name "*.tar.gz" -mtime +14 -delete
echo "$(date): Config backup completed" >> /var/log/backup-configs.log

Ebene 3: Home Assistant Backup

HA OS internes Backup, wöchentlich, auf Samba-Share am OptiPlex (homeassistant_backup). Retention: 3 Backups. Encryption aktiviert — Emergency Kit (Encryption Key) separat im Passwort-Manager sichern.

Ebene 4: Immich DB-Backups

Immich erstellt automatisch PostgreSQL-Dumps unter /mnt/storage/Photos/backups/.

Ebene 5: Offsite

Geplant: Hetzner Storage Box + Borgbackup für Immich-Fotos und Paperless-Dokumente (beides unersetzbar). Muss automatisiert sein.


Kritikalitäts-Matrix

KategorieDatenKritisch
UnersetzbarHA-Config, Zigbee-Pairing, Automationen
UnersetzbarImmich-Fotos, Paperless-Dokumente
AufwändigServarr-Configs, Pi-hole, Compose-FilesMittel
Re-downloadbarFilme, Serien, YouTubeNein

Drive-Übersicht

DevModellGehäuseMountPoolSMART-Monitoring
sdaSamsung SSD 840 EVO 500GBinternBootScrutiny ✅
sdbSeagate ST5000LM000-2U8170 (Expansion SW)USB 2/mnt/disk1MergerFSManuell ⚠️
sdcSeagate ST5000LM000-2AN170 (Portable)USB 3/mnt/disk2MergerFSManuell ⚠️
sddWD MyPassport ST5000LM000-2AN170USB 3/mnt/disk3MergerFSManuell ⚠️
sdeWD WD50NPJZ (Intenso-Gehäuse)USB 2/mnt/paritySnapRAID Parity (geplant)Scrutiny ✅

Nach SATA-Migration (ASM1166): alle fünf Drives von Scrutiny vollständig überwacht.


Drive Health Monitoring

Scrutiny

Läuft direkt auf dem Proxmox-Host (nicht in einem LXC) — notwendig für direkten Block-Device-Zugriff. Compose unter /opt/scrutiny/.

Einschränkung: Alle USB-Gehäuse (sdb, sdc, sdd, sde) blockieren SMART-Passthrough vollständig — USB-Bridge-Chips verweigern den Zugriff auf Linux. Nur sda (Boot-SSD, intern) wird von Scrutiny überwacht. Alle anderen Drives nur via CrystalDiskInfo auf Windows.

# /opt/scrutiny/config/collector.yaml
version: 1
devices:
  - device: /dev/sda
    type: sat
# /opt/scrutiny/docker-compose.yml
services:
  scrutiny:
    image: ghcr.io/analogj/scrutiny:master-omnibus
    container_name: scrutiny
    restart: unless-stopped
    cap_add:
      - SYS_RAWIO
    privileged: true
    ports:
      - "8080:8080"
    volumes:
      - /run/udev:/run/udev:ro
      - ./config:/opt/scrutiny/config
      - ./influxdb:/opt/scrutiny/influxdb
    devices:
      - /dev/sda
      - /dev/sdb
      - /dev/sdc
      - /dev/sdd

Manueller Scan: docker exec scrutiny /opt/scrutiny/bin/scrutiny-collector-metrics run

SMART-Werte die beobachtet werden

Für alle HDDs (sdb, sdc, sdd) gelten diese kritischen Indikatoren:

IDNameBedeutungGrenze
5Reallocated Sector CountSektoren physisch umgeschrieben weil defekt — direkte Vorwarnung für Ausfall>0 = sofort handeln
197Current Pending Sector CountSektoren die auf Verifikation warten — können noch gerettet werden>0 = beobachten
198Offline Uncorrectable Sector CountNicht wiederherstellbare Sektoren>0 = sofort handeln
187Reported Uncorrectable ErrorsFehler die ECC nicht korrigieren konnte>0 = sofort handeln
199UltraDMA CRC Error CountVerbindungsfehler (Kabel, Gehäuse-Bridge) — steigend = Kabel/Gehäuse tauschenBaseline merken, Anstieg beobachten

Für die Boot-SSD (sda, Samsung 840 EVO) zusätzlich:

AttributBedeutungGrenze
Reallocated SectorsWie bei HDDs>0 = beobachten
Health %Gesamtzustand laut Scrutiny<90% = handeln

Manuelle SMART-Kontrolle sdc/sdd

Da Scrutiny diese Drives nicht erreicht: CrystalDiskInfo auf Windows, Disks direkt anschließen. Alle 4–6 Wochen oder nach Auffälligkeiten.

Besonders beobachten: sdd (Seagate Expansion SW, /mnt/disk3) — hatte beim ersten Check 16.332 CRC-Fehler. Baseline und Verlauf in [[Homelab – Privat]].


Host-Tuning

EinstellungWert
ZFS ARC Limit2 GB (/etc/modprobe.d/zfs.conf)
ZFS Auto-TRIMon
ZFS ScrubMonatlich, 1. des Monats, 02:00
Swap4 GB ZFS zvol, swappiness=10

ZFS ARC auf 2 GB reduziert um RAM für Container freizugeben. Die Boot-SSD ist schnell genug dass der kleinere Cache keinen spürbaren Unterschied macht.