Files
datensicherung_rsync/README.md
T

256 lines
9.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# README Snapshot-Backup mit rsync
Dieses Skript erstellt Snapshots des Home-Verzeichnisses mit `rsync` und `--link-dest`.[cite:43][cite:34] Jeder Snapshot sieht wie ein vollständiges Backup aus, aber unveränderte Dateien werden per Hardlink wiederverwendet, sodass Speicherplatz gespart wird.[cite:34][cite:92]
## Zweck
Das Skript sichert den Inhalt von `HOME` auf ein externes Zielverzeichnis und legt dabei zeitgestempelte Snapshot-Ordner an.[cite:43] Über den Symlink `latest` wird immer auf den zuletzt erfolgreichen Sicherungsstand verwiesen.[cite:34][cite:92]
Typische Vorteile dieses Ansatzes:
- Einfach browsebare Backups, weil jeder Snapshot als normales Verzeichnis vorliegt.[cite:43][cite:91]
- Platzersparnis durch Hardlinks mit `--link-dest`.[cite:34][cite:92]
- Aufbewahrung mehrerer Sicherungsstände durch Rotation älterer Snapshots.[cite:43]
## Voraussetzungen
Für `--link-dest` sollte das Ziel auf einem Linux-Dateisystem liegen, das Hardlinks sauber unterstützt, etwa ext4, XFS oder btrfs.[cite:34][cite:91] Dateisysteme wie exFAT sind für diese Snapshot-Technik ungeeignet.[cite:34]
Benötigte Werkzeuge:
- `bash`
- `rsync`
- `readlink`
- `tee`
- Standard-Tools wie `mkdir`, `ln`, `ls`, `tail`, `rm`
## Verzeichnisaufbau
Das Skript erzeugt pro Lauf einen neuen Snapshot mit Zeitstempel.[cite:43][cite:92]
Beispiel:
```text
/run/media/hans/usbsicherung/jacboy_sicherung/
└── <hostname>/
├── 2026-04-28_10-30-00/
├── 2026-04-29_10-30-00/
├── latest -> /run/media/hans/usbsicherung/jacboy_sicherung/<hostname>/2026-04-29_10-30-00
└── logs/
```
## Funktionsweise
Das Skript prüft zunächst, ob das Zielverzeichnis existiert und beschreibbar ist, und legt anschließend Snapshot- und Log-Verzeichnisse an.[cite:43][cite:97] Danach wird `rsync` mit Archivoptionen sowie Ausschlüssen für nicht benötigte Verzeichnisse ausgeführt.[cite:43][cite:91]
Wenn bereits ein gültiger vorheriger Snapshot existiert, wird dieser über `--link-dest` als Referenz verwendet.[cite:34][cite:92] Unveränderte Dateien werden dann nicht erneut kopiert, sondern als Hardlinks im neuen Snapshot eingebunden.[cite:34]
Nach erfolgreichem Lauf aktualisiert das Skript den Symlink `latest` und entfernt ältere Snapshots oberhalb des konfigurierten Aufbewahrungswerts `KEEP`.[cite:43]
## Verwendete rsync-Optionen
| Option | Bedeutung |
|---|---|
| `-a` | Archivmodus: rekursiv kopieren und Metadaten erhalten.[cite:91][cite:43] |
| `-H` | Hardlinks in der Quelle erhalten.[cite:91] |
| `-A` | ACLs mitnehmen, sofern vorhanden.[cite:91] |
| `-X` | Erweiterte Attribute mitnehmen.[cite:91] |
| `-x` | Auf demselben Dateisystem bleiben; zusätzliche Mounts unterhalb von `HOME` werden nicht traversiert.[cite:91][cite:43] |
| `--delete` | Entfernt Dateien im neuen Snapshot, die in der Quelle nicht mehr vorhanden sind; ältere Snapshots bleiben dabei unberührt.[cite:91][cite:34] |
| `--delete-excluded` | Entfernt auch explizit ausgeschlossene Inhalte aus dem Ziel-Snapshot.[cite:91] |
| `--link-dest` | Verweist auf den letzten Snapshot, damit unveränderte Dateien per Hardlink wiederverwendet werden.[cite:34][cite:92] |
## Anpassbare Variablen
Die wichtigsten Variablen stehen am Anfang des Skripts:
```bash
SRC="${HOME}/"
DEST_BASE="/run/media/hans/usbsicherung/jacboy_sicherung"
KEEP=30
```
- `SRC`: Quellverzeichnis, standardmäßig das eigene Home-Verzeichnis.
- `DEST_BASE`: Basisverzeichnis auf dem Backup-Medium.
- `KEEP`: Anzahl der Snapshots, die aufbewahrt werden sollen.
Auch die Ausschlussliste kann direkt im Array `EXCLUDES` angepasst werden, zum Beispiel für Cache-, Download- oder temporäre Verzeichnisse.[cite:43]
## Verwendung
Syntax prüfen:
```bash
bash -n sicherung.sh
```
Skript ausführen:
```bash
bash sicherung.sh
```
Für einen sicheren Test kann vorübergehend `--dry-run` in die `RSYNC_OPTS` aufgenommen werden; dann zeigt `rsync` nur an, was passieren würde, ohne tatsächlich Daten zu schreiben.[cite:91][cite:43]
## Wiederherstellungstest
Ein Backup gilt erst dann als verlässlich, wenn sich Daten daraus testweise wiederherstellen und inhaltlich prüfen lassen.[cite:105][cite:109] Der empfohlene Weg ist, einen Snapshot nicht direkt ins echte Home-Verzeichnis zurückzuschreiben, sondern zunächst in ein separates Testverzeichnis zu restaurieren.[cite:105][cite:107]
### Testverzeichnis anlegen
```bash
mkdir -p /tmp/restore-test-home
```
### Snapshot auswählen und zurückspielen
Beispiel für einen Restore eines bestimmten Snapshots:
```bash
SNAP="/run/media/hans/usbsicherung/jacboy_sicherung/$(hostname -s)/2026-04-28_10-30-00"
rsync -aHAX \
"${SNAP}/" \
/tmp/restore-test-home/
```
Damit werden die Daten aus dem Snapshot mit Rechten, ACLs und erweiterten Attributen in das Testziel kopiert.[cite:91][cite:43] Alternativ kann auch nur ein Teilbereich wie `Documents/`, ein Projektordner oder `.config/` restauriert werden, um einzelne Anwendungsszenarien gezielt zu prüfen.[cite:105][cite:107]
### Integrität prüfen
Nach dem Restore sollten mehrere Prüfungen erfolgen:[cite:105][cite:110]
- Wichtige Dateien öffnen, etwa Dokumente, PDFs, Bilder oder Quellcode.[cite:105]
- Anwendungen testweise mit restaurierten Daten starten, zum Beispiel ein Projekt im Editor oder eine Konfiguration in einem Testprofil.[cite:107]
- Für wichtige Dateien Checksummen vergleichen, um die inhaltliche Identität sicherzustellen.[cite:110]
Beispiel mit `sha256sum`:
```bash
cd "${HOME}"
sha256sum wichtige_datei.odt
cd /tmp/restore-test-home
sha256sum wichtige_datei.odt
```
Die Prüfsummen sollten identisch sein.[cite:110]
### Worauf beim Restore zu achten ist
Beim Restore-Test sollten insbesondere Dateirechte, Symlinks, ACLs, xattrs und eventuelle Fehlermeldungen von `rsync` geprüft werden.[cite:91][cite:105] Gerade bei einem Restore auf ein anderes Dateisystem kann es Einschränkungen bei ACLs oder erweiterten Attributen geben.[cite:91]
### Empfehlung für die Praxis
Sinnvoll ist ein regelmäßiger Wiederherstellungstest, zum Beispiel quartalsweise, mit kurzer Dokumentation: verwendeter Snapshot, Testziel, geprüfte Dateien, Ergebnis und Auffälligkeiten.[cite:105][cite:109] Erst ein erfolgreich getesteter Restore macht aus einem Backup eine belastbare Datensicherung.[cite:105]
## Beispielskript
```bash
#!/usr/bin/env bash
set -Eeuo pipefail
SRC="${HOME}/"
DEST_BASE="/run/media/hans/usbsicherung/jacboy_sicherung"
HOST="$(hostname -s)"
STAMP="$(date +%F_%H-%M-%S)"
SNAPSHOT_DIR="${DEST_BASE}/${HOST}/${STAMP}"
LAST_LINK="${DEST_BASE}/${HOST}/latest"
LOG_DIR="${DEST_BASE}/${HOST}/logs"
LOG_FILE="${LOG_DIR}/backup-${STAMP}.log"
KEEP=30
log() {
local msg="[$(date +%F\ %T)] $*"
echo "${msg}"
if [[ -n "${LOG_FILE:-}" ]]; then
mkdir -p "$(dirname "${LOG_FILE}")"
echo "${msg}" >> "${LOG_FILE}"
fi
}
fail() {
log "FEHLER: $*"
exit 1
}
if [[ ! -d "${DEST_BASE}" ]]; then
fail "Zielbasis ${DEST_BASE} existiert nicht oder ist nicht gemountet. Bitte USB-Laufwerk prüfen."
fi
if [[ ! -w "${DEST_BASE}" ]]; then
fail "Zielbasis ${DEST_BASE} ist nicht beschreibbar. Rechte/Mount prüfen."
fi
mkdir -p "${SNAPSHOT_DIR}" "${LOG_DIR}"
log "Starte Backup: ${SRC} -> ${SNAPSHOT_DIR}"
RSYNC_OPTS=(
-aHAXx
--numeric-ids
--delete
--delete-excluded
--info=stats2,progress2
--human-readable
--partial
)
EXCLUDES=(
--exclude=".cache/"
--exclude="Downloads/"
--exclude=".local/share/Trash/"
--exclude=".gvfs/"
--exclude=".dotnet/"
--exclude=".codegpt/"
--exclude=".copilot/"
--exclude=".var/"
--exclude=".vscode/"
--exclude="temp/"
)
if [[ -L "${LAST_LINK}" ]] && [[ -d "$(readlink -f "${LAST_LINK}")" ]]; then
RSYNC_OPTS+=(--link-dest="$(readlink -f "${LAST_LINK}")")
log "Verwende link-dest: $(readlink -f "${LAST_LINK}")"
else
log "Kein gültiger letzter Snapshot gefunden es wird ein vollständiger Lauf erstellt."
fi
if rsync "${RSYNC_OPTS[@]}" \
"${EXCLUDES[@]}" \
"${SRC}" "${SNAPSHOT_DIR}/" | tee -a "${LOG_FILE}"
then
log "rsync erfolgreich abgeschlossen."
else
fail "rsync ist mit einem Fehler beendet worden."
fi
ln -sfn "${SNAPSHOT_DIR}" "${LAST_LINK}"
log "latest-Link zeigt jetzt auf ${SNAPSHOT_DIR}"
cd "${DEST_BASE}/${HOST}"
SNAPS=(20*/)
if (( ${#SNAPS[@]} > KEEP )); then
log "Rotationslauf: Es existieren ${#SNAPS[@]} Snapshots, KEEP=${KEEP}."
ls -1dt 20*/ | tail -n +$((KEEP + 1)) | while read -r old; do
log "Lösche alten Snapshot: ${old}"
rm -rf -- "${old}"
done
else
log "Rotationslauf: Es müssen keine alten Snapshots gelöscht werden (Anzahl: ${#SNAPS[@]}, KEEP=${KEEP})."
fi
log "Backup abgeschlossen."
```
## Sicherheitshinweise
Ein erster Testlauf sollte als Dry-Run erfolgen, um Ausschlüsse, Zielpfad und Verhalten zu prüfen, bevor echte Daten geschrieben oder gelöscht werden.[cite:91][cite:43] Das Zielverzeichnis sollte nicht innerhalb des zu sichernden Home-Verzeichnisses liegen, um Rekursionen und ungewollte Mitsicherungen zu vermeiden.[cite:43]
Bei Verwendung von `--delete` gilt: Gelöschte Dateien verschwinden aus dem neu erzeugten Snapshot, bleiben aber in älteren Snapshots weiterhin vorhanden.[cite:34][cite:92] Genau dadurch entsteht die gewünschte Snapshot-Historie.[cite:92]
## Mögliche Erweiterungen
Sinnvolle nächste Ausbaustufen wären ein optionaler `--dry-run`-Schalter, eine Prüfung des tatsächlichen Mountpoints per `mountpoint`, sowie eine Automatisierung über `systemd`-Timer statt manueller Ausführung.[cite:97][cite:43]