April 2026:
Nachdem ich etwas mehr als 1 Jahr Docker unter macOS 13 verwendet habe und mit allen möglichen Hürden zu kämpfen hatte, wurde auf Debian 12, ein reines minimalistisch installiertes Linux, migriert. Ich denke, ich kann zufrieden sein.
Das System ist auf hohe Verfügbarkeit der Daten und maximale Stromersparnis im 24/7-Betrieb ausgelegt.
Der i5-5675C Vorteil: > „Warum diese spezielle CPU? Dank des integrierten 128MB eDRAM (L4-Cache) bietet dieser Broadwell-Chip eine Effizienz, die viele Nachfolgegenerationen im Idle-Bereich erst viel später erreichten. Gepaart mit dem S1200V3RP Server-Board ergibt das eine stabile Basis mit IPMI-Support bei nur 21W Leistungsaufnahme – ideal für einen 24/7 Home-Server mit anspruchsvoller Docker-Umgebung.“

Speicher-Architektur (LVM Mirroring)
Um Ausfallsicherheit zu gewährleisten, wurde konsequent auf LVM-Mirroring gesetzt. Dies ermöglicht den Austausch einer defekten SSD im laufenden Betrieb ohne Datenverlust.
Volume Group
system: Spiegelt das Betriebssystem (Debian 12).Volume Group
docker: Trennung von OS und Anwendungsdaten. Alle Docker-Volumes und Container-Configs liegen hier.Vorteil: Sollte eine SSD sterben, läuft der Server ohne Unterbrechung weiter.
Mein Container:

Die Backup-Strategie (3-Stufen-Konzept)
Die Sicherung erfolgt vollautomatisch über das Tool Restic, orchestriert durch Systemd-Timer auf dem Host und visualisiert durch Backrest im Docker-Container.
Stufe 1: Lokale SSD-Sicherung (6-stündlich)
Ziel: 500 GB USB-SSD (
/mnt/restic-usb)Intervall: Alle 6 Stunden via Systemd-Timer.
Besonderheit: Extrem schnelle Wiederherstellung von versehentlich gelöschten Dateien.
Stufe 2: NAS-Sicherung (Nächtlich)
Ziel: Synology NAS via NFS/SMB (
/mnt/backup)- Intervall: Alle 24 Stunden, 3 Uhr nachts, via Systemd-Timer.
Workflow: Das System weckt das NAS per Wake-on-LAN (WOL), mountet das Dateisystem, führt den Restic-Snapshot aus und fährt das NAS danach wieder herunter. Sollte das Synology NAS bereits eingeschaltet gewesen sein, wird es natürlich nicht heruntergefahren.
Effizienz: Das NAS verbraucht nur Strom, wenn es wirklich benötigt wird.
Stufe 3: Monitoring & GUI
Tool: Backrest (Web-Interface für Restic)
Funktion: Visualisierung aller Snapshots, einfaches Browsen in Backups und schneller Datei-Restore ohne Kommandozeile.

The Ultimate Persistent NAS-Backup Orchestrator
/usr/local/bin/restic-backup-all.sh
#!/usr/bin/env bash
set -euo pipefail
source /etc/restic/env
LOG="/var/log/restic-backup-n-p.log"
LOCKFILE="/run/restic-backup-n-p.lock"
PAPERLESS="/srv/docker/paperless/docker-compose.yml"
NEXTCLOUD="/srv/docker/nextcloud/docker-compose.yml"
NAS_IP="192.168.1.5"
NAS_USER="credel"
# -------------------------
# NAS STATE (persistent)
# -------------------------
NAS_STATE_FILE="/run/restic-nas-started.lock"
NAS_STARTED_BY_SCRIPT=0
[[ -f "$NAS_STATE_FILE" ]] && NAS_STARTED_BY_SCRIPT=1
log() {
echo "[$(date '+%F %T')] $*" | tee -a "$LOG"
}
fail() {
log "ERROR: $*"
exit 1
}
nas_is_up() {
ssh -o BatchMode=yes \
-o ConnectTimeout=2 \
-o StrictHostKeyChecking=no \
"$NAS_USER@$NAS_IP" "exit" >/dev/null 2>&1
}
start_nas_if_needed() {
log "CHECK NAS STATE"
if nas_is_up; then
log "NAS already running - skip start"
return 0
fi
log "START NAS (WOL)"
echo "1" > "$NAS_STATE_FILE"
NAS_STARTED_BY_SCRIPT=1
/usr/local/bin/syno6x6-start.sh
log "WAIT NAS READY"
for i in {1..90}; do
if nas_is_up; then
log "NAS READY"
log "NAS STORAGE CHECK"
for j in {1..30}; do
if mountpoint -q /mnt/backup && [[ -d /mnt/backup/restic ]]; then
log "NAS STORAGE READY"
break
fi
sleep 2
done
mountpoint -q /mnt/backup || fail "NAS storage not mounted"
[[ -d /mnt/backup/restic ]] || fail "RESTIC repo missing"
return 0
fi
sleep 2
done
fail "NAS not reachable after startup"
}
stop_nas_if_started_by_script() {
if [[ "${NAS_STARTED_BY_SCRIPT:-0}" -ne 1 ]]; then
log "NAS was already running → skip shutdown"
return 0
fi
log "STOP NAS"
ssh "$NAS_USER@$NAS_IP" \
"echo '**************' | sudo -S /usr/syno/sbin/synoshutdown --shutdown" \
>/dev/null 2>&1 || log "NAS shutdown failed or already offline"
rm -f "$NAS_STATE_FILE"
}
cleanup() {
log "START containers"
docker compose -f "$PAPERLESS" start || true
docker compose -f "$NEXTCLOUD" start || true
sleep 10
log "HEALTH CHECK"
docker ps --format '{{.Names}} {{.Status}}' | tee -a "$LOG"
stop_nas_if_started_by_script
rm -f "$LOCKFILE"
}
trap cleanup EXIT
# -------------------------
# LOCK
# -------------------------
if [[ -e "$LOCKFILE" ]]; then
fail "Backup already running"
fi
touch "$LOCKFILE"
log "BACKUP START"
# -------------------------
# NAS HANDLING
# -------------------------
start_nas_if_needed
# -------------------------
# PRECHECKS
# -------------------------
docker info >/dev/null 2>&1 || fail "Docker not running"
restic snapshots >/dev/null 2>&1 || fail "Restic repo not reachable"
# -------------------------
# STOP STACKS
# -------------------------
# -------------------------
# STOP STACKS (DETERMINISTIC FAST MODE)
# -------------------------
log "STOP containers (paperless + nextcloud)"
# 1) Paperless zuerst (kritisch, DB nah)
docker compose -f "$PAPERLESS" stop --timeout 30 || {
log "WARNING: Paperless graceful stop failed → forcing"
docker compose -f "$PAPERLESS" kill || true
}
# 2) Nextcloud Stack (worker + DB + redis)
docker compose -f "$NEXTCLOUD" stop --timeout 30 || {
log "WARNING: Nextcloud graceful stop failed → forcing"
docker compose -f "$NEXTCLOUD" kill || true
}
sleep 5
# 3) Targeted cleanup for known stubborn containers
for c in nc_cron nc_app nc_redis nc_db; do
if docker ps --format '{{.Names}}' | grep -q "^${c}$"; then
log "FORCE STOP (stubborn container): $c"
docker stop --time=20 "$c" || docker kill "$c" || true
fi
done
sleep 3
# 4) Final verification (non-blocking)
log "STOP VERIFY"
docker ps --format '{{.Names}} {{.Status}}' | tee -a "$LOG"
# -------------------------
# BACKUP CORE
# -------------------------
log "RESTIC BACKUP"
restic backup \
/srv/docker/nextcloud \
/srv/docker/paperless \
/etc \
/root \
/home \
/usr/local \
/var/spool/cron \
/var/lib/systemd
# -------------------------
# BACKUP ALL OTHER DOCKER CONTAINERS
# -------------------------
log "DOCKER CONTAINER EXPORT (NON CORE)"
docker ps --format '{{.Names}}' \
| grep -v -E "paperless|nc_" \
> /tmp/docker-containers.txt
restic backup /tmp/docker-containers.txt
for c in $(docker ps --format '{{.Names}}' | grep -v -E "paperless|nc_"); do
docker inspect "$c" > "/tmp/docker-$c.json"
done
restic backup /tmp/docker-*.json || true
# -------------------------
# RETENTION
# -------------------------
log "RETENTION POLICY"
restic forget \
--keep-daily 7 \
--keep-weekly 4 \
--keep-monthly 6 \
--prune
log "BACKUP DONE"
/usr/local/bin/restic-backup-usb.sh
#!/bin/bash set -euo pipefail export RESTIC_REPOSITORY=/mnt/restic-usb/repo export RESTIC_PASSWORD_FILE=/root/.restic/password-usb # ???? WICHTIG: systemd environment fix export HOME=/root export XDG_CACHE_HOME=/root/.cache LOGTAG="[RESTIC-USB]" echo "$LOGTAG START $(date)" # Safety check: USB muss gemountet sein if ! mountpoint -q /mnt/restic-usb; then echo "$LOGTAG USB not mounted - abort" exit 1 fi # Backup restic backup \ /etc \ /home \ /root \ /srv/docker \ /usr/local \ --exclude "/srv/docker/*/tmp" \ --exclude "/var/cache" \ --exclude "/var/tmp" \ --exclude "/swapfile" # Retention: 1 Jahr restic forget \ --keep-daily 30 \ --keep-weekly 12 \ --keep-monthly 12 \ --prune echo "$LOGTAG DONE $(date)"
Zum Schluss noch:
Das „Efficiency-Tuning“ Logbuch
Die Fehlentscheidung: i5-9500 & B360M
Versprechen: 15W Idle.
Realität: ~20W Idle.
Lerneffekt: Neuere Consumer-Hardware ist nicht automatisch effizienter als optimierte Server-Hardware, wenn man die restlichen Komponenten (LVM, mehrere SSDs) einbezieht.
Energetischer Kontext (Balkonkraftwerk)
PV-Anlage: 2000W Peak / 6,3kWh Akku.
Grundlast Nacht: 75W gesamt.
Server-Anteil: 21W (~28%).
Fazit: Dank des großen Speichers wird der Server zu 100% autark durch Sonnenenergie betrieben, selbst in bewölkten Phasen reicht die Kapazität locker aus.
Ganz zum Schluss noch:
Dieses Setup hat mich nicht Stunden, es hat etliche Tage gebraucht um hier endlich an diesem für mich finalen Punkt anzukommen. Sicherlich wird hier und da noch zu optimieren sein. Vor allem muss ein (auch Desaster) Recovery simuliert und dokumentiert werden.
#