
🌐 Auch auf: English · Français · Español
Über dieses NAS habe ich schon zweimal geschrieben – erst über den Aufbau mit RAIDZ1 unter Debian 13, dann im Nachtrag darüber, wie Scrub und Trim tatsächlich geplant werden, samt dem Alarm, der keiner war.
Diesmal geht es um Versionierung. Seit Jahren lautet meine Antwort auf „Wie bekomme ich die Version dieser Datei von gestern zurück?“ rdiff-backup, und das ist ehrlich gesagt eine gute Antwort. Installiert ist es auf der Kiste immer noch:
$ rdiff-backup --version
rdiff-backup 2.2.6Aber mit dem Pool auf OpenZFS lag plötzlich ein zweiter Mechanismus auf dem Tisch – einer, der dasselbe Problem aus einer völlig anderen Richtung löst. Also habe ich einen Abend damit verbracht, zu verstehen, wie ZFS-Snapshots wirklich funktionieren, was sie kosten und wo sie das Tool schlagen, das ich bisher zufrieden benutzt habe. Dieser Beitrag ist dieser Abend, inklusive der Stellen, die ich beim ersten Versuch falsch gemacht habe.
🔄 Zwei Antworten auf dieselbe Frage
Beide Tools beantworten „Gib mir den Stand von vor N Tagen.“ Sie sind sich nur grundlegend uneinig darüber, wann die Arbeit passiert.
rdiff-backup hält einen einfachen Spiegel des neuesten Stands vor, dazu umgekehrte Inkremente in rdiff-backup-data/. Für ein Backup läuft es den kompletten Quellbaum ab, vergleicht ihn mit dem Spiegel und berechnet mit librsync binäre Deltas für alles, was sich geändert hat. Die Arbeit fällt zum Backup-Zeitpunkt an, und sie wächst mit der Datenmenge – nicht mit der Menge der Änderungen. Eine alte Version wiederherzustellen heißt: beim Spiegel anfangen und die Inkremente rückwärts anwenden.
ZFS-Snapshots machen nichts davon, denn das Dateisystem weiß es bereits. ZFS ist Copy-on-Write: Wenn du einen Block änderst, wird er nie an Ort und Stelle überschrieben, sondern die neue Version landet woanders und der Zeiger wird umgebogen. Der alte Block würde normalerweise zu freiem Speicher.
Ein Snapshot sagt genau eine Sache: Behalte jeden Block, auf den dieses Dataset gerade zeigt.
Es gibt nichts zu scannen, nichts zu vergleichen, nichts zu berechnen. Deshalb sieht das Anlegen eines Snapshots so aus:
$ zfs list -t snapshot -o name,used,creation
NAME USED CREATION
storage/user1@auto-2026-09-11_1250 0B Fr Sep 11 12:50 2026
storage/user2@auto-2026-09-11_1250 0B Fr Sep 11 12:50 2026
storage/nextcloud@auto-2026-09-11_1250 0B Fr Sep 11 12:50 2026
storage/user3@auto-2026-09-11_1250 0B Fr Sep 11 12:50 20260B. Vier Snapshots über 1,8 TB, in Millisekunden erstellt, belegen nichts. Alle haben gelächelt, das Foto ist im Kasten, und der Film hat nichts gekostet – weil es keinen Film gibt. Ein Snapshot ist keine Kopie deiner Daten. Er ist ein Versprechen, die aktuelle Version nicht wegzuwerfen.
⚡ Ist das wirklich schneller? Ja, aber genau hinschauen, was
Das Anlegen eines Snapshots ist O(1). Es dauert dieselben paar Millisekunden, egal ob das Dataset 14 GB oder 1,17 TB enthält, weil die Kosten überhaupt nicht von den Daten abhängen – nur davon, einen Satz Referenzen einzufrieren.
rdiff-backup muss bei jedem einzelnen Lauf den Baum durchgehen, um herauszufinden, was sich geändert hat. Auf storage/user3 (1,17 TB) ist das eine spürbare Menge I/O und Laufzeit, selbst in einer Nacht, in der sich nichts bewegt hat.
Beim Wiederherstellen ist es dieselbe Geschichte, nur umgekehrt. Jeder ZFS-Snapshot ist ein vollständiger, direkt lesbarer Baum – kein Rekonstruktionsschritt, keine Inkremente, kein Warten:
$ ls /storage/nextcloud/.zfs/snapshot/auto-2026-09-11_1250/
instance-a instance-bDas ist der Stand von genau diesem Moment, sofort durchsuchbar mit ls, cp, rsync oder einem Dateimanager.
Die ehrliche Einschränkung, denn genau hier wird der Vergleich gern übertrieben: Ein Snapshot versioniert nur Daten, die bereits im Pool liegen. Er schafft nichts aufs NAS. Daten von einem Server auf diese Kiste zu bekommen, bleibt der Job von rsync – der Snapshot ersetzt die Versionierungsschicht, nicht die Übertragung. Und rdiff-backup kann per SSH auf eine völlig andere Maschine schreiben, was Snapshots grundsätzlich nicht können. Mehr dazu weiter unten.
💾 Und der Platz?
Beide Ansätze sind effizient, aber auf unterschiedliche Weise, und die ehrliche Antwort enthält ein „kommt drauf an“.
rdiff-backup speichert komprimierte binäre Deltas mit Byte-Granularität. Ändere drei Zeilen in einem Datenbank-Dump, und das Inkrement ist winzig – für dieses Muster wirklich beeindruckend.
ZFS behält ganze geänderte Records. In diesem Pool sind das 128 KB:
$ zfs get recordsize,compression,compressratio storage/nextcloud
NAME PROPERTY VALUE
storage/nextcloud recordsize 128K
storage/nextcloud compression lz4
storage/nextcloud compressratio 1.03xEine Ein-Byte-Änderung an einer riesigen Datei hält also einen 128-KB-Block fest, wo rdiff-backup vielleicht ein paar hundert Bytes gespeichert hätte. Gröber, keine Frage.
Was ZFS dafür zurückgibt:
- Kein Spiegel-Overhead. Der neueste Stand bei rdiff-backup ist eine komplette zweite Kopie von allem. Snapshots teilen sich jeden unveränderten Block mit den Live-Daten – es gibt überhaupt keine doppelte Basis.
- Keine Buchhaltung pro Version. Dreißig Snapshots eines unveränderten Datasets kosten dreißigmal nichts.
- lz4 auf ganzer Linie, transparent, für Live-Daten und Snapshots gleichermaßen.
Die compressratio von 1,03x verdient einen ehrlichen Hinweis: Meine Daten sind Fotos und Medien, also schon komprimiert, da bringt mir lz4 hier fast nichts. Das spricht nicht gegen lz4 – es ist das korrekte Ergebnis für diese Inhalte, und auf einem Dataset voller Logs oder Text sähe das ganz anders aus.
Unterm Strich für typische gemischte Daten aus Haushalt und Büro: beim Platz vergleichbar, im Betrieb drastisch günstiger. Für das spezielle Muster winziger, häufiger Änderungen in sehr großen Dateien gewinnen die Byte-Deltas von rdiff-backup bei den Bytes weiterhin.
📁 Wo Snapshots wohnen: das Verzeichnis, das nicht da ist
Snapshots sind keine Dateien, auf die du einen Dateimanager loslassen kannst. Aber ZFS bietet dir ein Fenster, das sich wie ein ganz normales Verzeichnis verhält:
$ ls /storage/nextcloud/.zfs/snapshot/
auto-2026-09-11_1250Der Haken, über den jeder genau einmal stolpert: .zfs ist standardmäßig versteckt und taucht in ls -la nicht auf. Es ist kein normaler Verzeichniseintrag, sondern synthetisch. Tipp den Pfad trotzdem ein, und es funktioniert.
$ zfs get snapdir storage/nextcloud
NAME PROPERTY VALUE SOURCE
storage/nextcloud snapdir hidden defaultAlles darunter ist schreibgeschützt. Du kannst einen Snapshot beim Durchstöbern nicht beschädigen und nicht versehentlich hineinschreiben. Du kannst nur herauskopieren – und genau das willst du bei einer Wiederherstellung.
⏱️ Das Skript, und warum diesmal systemd-Timer
Im Beitrag über Scrub und Trim habe ich festgestellt, dass Debian die ZFS-Wartung über /etc/cron.d/zfsutils-linux plant und die systemd-Timer zwar mitliefert, aber deaktiviert. Für Snapshots bin ich bewusst den anderen Weg gegangen:
[Timer]
OnCalendar=daily
RandomizedDelaySec=15m
Persistent=truePersistent=true ist der Grund. Ist das NAS um Mitternacht ausgeschaltet, überspringt cron den Tag einfach und sagt niemandem Bescheid. systemd holt den verpassten Job beim nächsten Boot nach. Bei etwas, dessen ganzer Wert darin besteht, da zu sein, bevor du es brauchst, ist stilles Überspringen von Tagen kein akzeptabler Fehlermodus – und ich hatte gerade einen ganzen Beitrag über Dinge geschrieben, die still versagen.
RandomizedDelaySec verteilt die vier Datasets, damit sie nicht alle in derselben Sekunde loslaufen.
Das Rotationsskript hat genau einen Job: einen Snapshot anlegen und dann die ältesten bis auf die Aufbewahrungsanzahl abräumen.
#!/bin/bash
# /usr/local/sbin/zfs-snapshot-rotate.sh
set -euo pipefail
DATASET="${1:?Dataset missing}"
KEEP="${2:-30}"
PREFIX="auto-"
zfs list -H -o name "$DATASET" >/dev/null 2>&1 || {
echo "Dataset $DATASET does not exist" >&2; exit 1; }
zfs snapshot "${DATASET}@${PREFIX}$(date +%Y-%m-%d_%H%M)"
# Newest first, keep the first $KEEP, everything after that goes.
# "|| true": grep returns 1 when nothing matches yet, which is not an error.
mapfile -t old < <(
zfs list -H -t snapshot -o name -S creation -r "$DATASET" 2>/dev/null \
| grep -E "^${DATASET}@${PREFIX}" \
| tail -n "+$((KEEP + 1))" || true
)
for snap in "${old[@]}"; do
[ -n "$snap" ] || continue
[[ "$snap" == "${DATASET}@${PREFIX}"* ]] || continue
[[ "$snap" == *"@"* ]] || continue
zfs destroy "$snap"
doneDrei Schutzprüfungen, bevor irgendetwas gelöscht wird, und das ist kein Paranoia-Theater. zfs destroy nimmt einen Snapshot-Namen und einen Dataset-Namen an genau derselben Argumentposition an. Wäre $snap jemals leer oder abgeschnitten, würde zfs destroy storage/user3 1,17 TB Familienfotos mitnehmen, ohne eine einzige Rückfrage. Die @-Prüfung macht das strukturell unmöglich.
Auch der Präfix-Filter zählt: Nur Snapshots, die dieses Skript selbst angelegt hat, kommen fürs Löschen in Frage. Alles, was von Hand oder von einem anderen Tool erstellt wurde, ist für das Skript unsichtbar.
🧪 Den Löschpfad testen, denn natürlich testet man den Löschpfad
Ein ungetestetes zfs destroy in einem nächtlichen Timer, der auf deine eigenen Daten zielt, willst du nicht im ungünstigsten Moment kennenlernen. Bevor ich ihm vertraut habe, habe ich die Rotation also mit KEEP=1 gegen das kleinste Dataset laufen lassen, damit sie wirklich etwas löschen muss:
--- before ---
storage/user1@auto-2026-09-11_1252
--- rotate with keep=1 ---
--- after ---
storage/user1@auto-2026-09-11_1253
--- dataset intact? ---
storage/user1 14.4GAlter Snapshot weg, neuer bleibt, Dataset unangetastet. Überprüft statt angenommen.
Eine Einschränkung, auf die ich beim Testen gestoßen bin und die ich bewusst behalte: Die Namen enthalten %H%M, also kollidieren zwei Läufe innerhalb derselben Minute mit „dataset already exists“. Für einen täglichen Timer egal, für jeden, der von Hand testet, ein Zwei-Sekunden-Rätsel. Jetzt weißt du es.
🦠 Der Ransomware-Aspekt, und hier zahlt es sich wirklich aus
Mehrere Leute synchronisieren per Windows-Desktop-Client mit meiner Nextcloud – dem, der die Cloud als Laufwerk im Explorer einbindet. Das ist bequem und bedeutet zugleich, dass die Stellenbeschreibung des Clients lautet: „Geänderte Dateien bemerken, hochladen.“ Ransomware auf so einem Rechner verschlüsselt die lokalen Dateien, und der Client tut pflichtbewusst genau das, wofür er gebaut wurde.
Das ist das Szenario, in dem der Unterschied zwischen einem Spiegel und einer versionierten Historie aufhört, akademisch zu sein. Ein reiner Spiegel bildet den verschlüsselten Zustand originalgetreu nach. Eine versionierte Historie lässt dich hinter ihn zurückgehen.
Die Reihenfolge bei der Wiederherstellung, die tatsächlich funktioniert:
Zuerst die Synchronisation stoppen. Den betroffenen Client trennen oder Nextcloud in den Wartungsmodus versetzen. Wer in eine laufende Sync-Beziehung mit einem infizierten Endgerät hinein wiederherstellt, bekommt seine Wiederherstellung gleich wieder verschlüsselt – und hat obendrein Zeit verloren.
Danach die eigenen Ebenen von Nextcloud probieren. Serverseitiger Papierkorb und Dateiversionierung sind mit Abstand der günstigste Weg, und für alles unterhalb eines Massenereignisses reichen sie meist schon allein.
Dann zu den Snapshots greifen. Und hier kommt es auf genau eine Unterscheidung an:
zfs rollbacksetzt das Dataset an Ort und Stelle zurück und vernichtet unwiderruflich alles Neuere, auch neuere Snapshots. Verschätzt du dich beim Zeitpunkt, ist dein zweiter Versuch weg.- Herauskopieren aus
.zfs/snapshot/<name>/verändert überhaupt nichts. Mach es zehnmal, vergleiche die Ergebnisse, lass dir Zeit.
Nimm das Zweite. Rollback ist ein scharfes Werkzeug für einen anderen Job.
Du musst auch nicht raten, wann der Schaden begonnen hat – das war mein erster Impuls. ZFS sagt es dir:
$ zfs diff storage/nextcloud@auto-2026-09-10_0000 \
storage/nextcloud@auto-2026-09-11_0000Der Snapshot, in dem plötzlich Tausende Dateien als geändert auftauchen, ist der nach dem Ereignis. Nimm den davor.
📤 Wo rdiff-backup weiterhin gewinnt, und das ist keine Kleinigkeit
Snapshots liegen im Pool. Dieselben drei Platten, dasselbe Schicksal. RAIDZ1 überlebt eine tote Platte; es überlebt keinen Brand, keinen Diebstahl, keinen Controller, der das Array mit in den Abgrund reißt, und niemanden mit Root-Rechten, der zfs destroy ausführt.
Snapshots schützen also vor logischen Schäden – Ransomware, einer vertippten Löschung, einer schiefgelaufenen Synchronisation. Gegen physischen Verlust tun sie nichts. Das ist die Hälfte, die rdiff-backup schon immer gut abgedeckt hat, indem es per SSH auf komplett getrennte Hardware schreibt.
ZFS hat hier eine eigene Antwort, und die fügt sich schön ein:
$ zfs send storage/nextcloud@auto-2026-09-11_1250 > /mnt/usb/nextcloud.zfs
$ zfs send storage/nextcloud@auto-2026-09-11_1250 | zfs recv usbpool/nextcloudzfs send -i überträgt danach nur noch das Delta zwischen zwei Snapshots, und damit wird „externe Platte, die in einer Schublade wohnt“ praktikabel statt zum Wochenendprojekt.
Mein Fazit lautet nicht „rdiff-backup ersetzen“. Sondern: Diese Tools standen nie wirklich in Konkurrenz:
- Snapshots – sofortige, kostenlose, unbegrenzte Historie gegen logische Schäden, genau dort, wo die Daten liegen
- Eine Kopie auf getrennter Hardware – das Einzige, was den Verlust der Maschine selbst überlebt
🔧 Die Befehle, die man sich wirklich merken sollte
Inspektion:
$ zfs list -t snapshot -o name,used,creation # what exists, how big, when
$ zfs list -o name,used,avail -r storage # datasets and space
$ systemctl list-timers 'zfs-snapshot@*' # when did/will it run
$ journalctl -u 'zfs-snapshot@*' --since today # did it workDurchsuchen und wiederherstellen:
$ ls /storage/<dataset>/.zfs/snapshot/ # available points in time
$ ls /storage/<dataset>/.zfs/snapshot/auto-*/ # the files themselves
$ zfs diff <snapshot-a> <snapshot-b> # what changed between them
$ rsync -a /storage/x/.zfs/snapshot/<snap>/foo/ /restore/foo/Manuelle Operationen:
$ zfs snapshot storage/user3@before-something-risky
$ zfs destroy storage/user3@before-something-risky
$ zfs hold keep storage/user3@important # protect from deletionzfs hold wird unterschätzt. Es sorgt dafür, dass sich ein Snapshot weigert, gelöscht zu werden, bis du ihn ausdrücklich freigibst – ideal für den einen bekannt guten Stand, der jede Rotationslogik überleben soll, auch deine eigene.
⚠️ Zwei Dinge, die du wissen solltest, bevor du dich darauf verlässt
Die Aufbewahrung ist eine echte Grenze. Hier dreißig Tage. Ein Vorfall, der länger unbemerkt bleibt, rotiert außer Reichweite. Für ein aktiv genutztes System komfortabel; für kalte Archive lieber eine monatliche Stufe ergänzen, statt zu hoffen.
Snapshots folgen Datasets, nicht Verzeichnissen. Das hat mich beim Überprüfen meiner eigenen Arbeit erwischt. /storage enthält vier Datasets – und ein einfaches Verzeichnis, das kein Dataset ist und deshalb still und leise gar nichts bekommt:
$ zfs list /storage/gitlab-migration
NAME USED AVAIL REFER MOUNTPOINT
storage 1.78T 1.73T 160K /storageEs wurde auf das übergeordnete Dataset aufgelöst, nicht auf sich selbst. Mach morgen ein mkdir /storage/something, und es erbt keine Snapshot-Richtlinie, ohne jede Warnung. Nimm stattdessen zfs create storage/something, und es bekommt von allem sein Eigenes – Snapshots, Quotas, Properties. Kostet nichts und ist der Unterschied zwischen Schutz, den du hast, und Schutz, den du nur annimmst.
Was wirklich hängen bleibt
Was mich dabei am meisten beeindruckt hat, war weder die Platzeffizienz noch die Geschwindigkeit. Sondern wo die Arbeit passiert.
rdiff-backup muss, wie fast jedes Backup-Tool, losziehen und herausfinden, was sich geändert hat – Bäume ablaufen, vergleichen, rechnen. Das ist ein enormer Aufwand, um etwas wiederzuentdecken, das das Dateisystem in Echtzeit mitangesehen und dann vergessen hat.
ZFS vergisst nicht. Copy-on-Write bedeutet, dass die Information schon da war; ein Snapshot verzichtet nur darauf, sie wegzuwerfen. Deshalb geht es sofort, und deshalb kostet es nichts, bis sich tatsächlich etwas ändert.
Eine gute Erinnerung daran, dass die interessante Frage bei Infrastruktur meist nicht lautet „Welches Tool ist besser?“, sondern „Wer kennt die Antwort schon, und frage ich ihn – oder rechne ich sie jede Nacht um 3 Uhr neu aus?“




