
🌐 Aussi en: English · Deutsch · Español
J’ai déjà écrit deux fois sur ce NAS : d’abord sa construction en RAIDZ1 sous Debian 13, puis l’addendum sur la façon dont le scrub et le trim sont réellement planifiés, et sur l’alerte qui n’en était pas une.
Cette fois, il est question de versionnage. Depuis des années, ma réponse à « comment récupérer la version d’hier de ce fichier ? » s’appelle rdiff-backup, et c’est sincèrement une bonne réponse. Il est d’ailleurs toujours installé sur la machine :
$ rdiff-backup --version
rdiff-backup 2.2.6Mais construire le pool sur OpenZFS a mis un second mécanisme sur la table – un mécanisme qui résout le même problème par un tout autre bout. J’ai donc passé une soirée à comprendre comment fonctionnent vraiment les snapshots ZFS, ce qu’ils coûtent et où ils battent l’outil que j’utilisais jusque-là avec plaisir. Cet article, c’est cette soirée, y compris les points sur lesquels je me suis trompé du premier coup.
🔄 Deux façons de répondre à la même question
Les deux outils répondent à « donne-moi l’état d’il y a N jours ». Ils sont simplement en désaccord total sur le moment où le travail a lieu.
rdiff-backup conserve un simple miroir de l’état le plus récent, plus des incréments inversés dans rdiff-backup-data/. Pour faire une sauvegarde, il parcourt toute l’arborescence source, la compare au miroir et calcule avec librsync des deltas binaires pour tout ce qui a changé. Le travail a lieu au moment de la sauvegarde, et il croît avec la quantité de données – pas avec la quantité de changements. Restaurer une ancienne version signifie partir du miroir et appliquer les incréments à rebours.
Les snapshots ZFS ne font rien de tout cela, car le système de fichiers le sait déjà. ZFS fonctionne en copy-on-write : quand vous modifiez un bloc, il n’est jamais écrasé sur place ; la nouvelle version est écrite ailleurs et le pointeur est redirigé. L’ancien bloc deviendrait normalement de l’espace libre.
Un snapshot dit exactement une chose : garde chaque bloc vers lequel ce dataset pointe en ce moment.
Rien à scanner, rien à comparer, rien à calculer. Voilà pourquoi en créer un ressemble à ceci :
$ 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. Quatre snapshots couvrant 1,8 To, pris en quelques millisecondes, qui n’occupent rien. Tout le monde a souri, la photo est dans la boîte, et la pellicule n’a rien coûté – parce qu’il n’y a pas de pellicule. Un snapshot n’est pas une copie de vos données. C’est la promesse de ne pas jeter la version actuelle.
⚡ Est-ce vraiment plus rapide ? Oui, mais précisons bien quoi
La création d’un snapshot est en O(1). Elle prend les mêmes quelques millisecondes, que le dataset contienne 14 Go ou 1,17 To, parce que le coût ne dépend absolument pas des données – seulement du gel d’un ensemble de références.
rdiff-backup doit parcourir l’arborescence à chaque exécution pour découvrir ce qui a changé. Sur storage/user3 (1,17 To), cela représente une quantité non négligeable d’E/S et de temps, même une nuit où rien n’a bougé.
Pour la restauration, c’est la même histoire à l’envers. Chaque snapshot ZFS est une arborescence complète, directement lisible – pas d’étape de reconstruction, pas d’incréments à appliquer, pas d’attente :
$ ls /storage/nextcloud/.zfs/snapshot/auto-2026-09-11_1250/
instance-a instance-bC’est l’état à cet instant précis, consultable immédiatement avec ls, cp, rsync ou un gestionnaire de fichiers.
La réserve honnête, car c’est là que la comparaison est souvent survendue : un snapshot ne versionne que les données déjà présentes sur le pool. Il ne transfère rien vers le NAS. Amener les données d’un serveur sur cette machine reste le travail de rsync – le snapshot remplace la couche de versionnage, pas le transfert. Et rdiff-backup peut écrire sur une machine complètement différente via SSH, ce que les snapshots ne peuvent catégoriquement pas faire. J’y reviens plus bas.
💾 Et l’espace ?
Les deux approches sont efficaces, mais pas de la même manière, et la réponse honnête contient un « ça dépend ».
rdiff-backup stocke des deltas binaires compressés à l’octet près. Modifiez trois lignes dans un dump de base de données et l’incrément est minuscule – vraiment impressionnant pour ce cas de figure.
ZFS conserve des records modifiés entiers. Sur ce pool, cela fait 128 Ko :
$ zfs get recordsize,compression,compressratio storage/nextcloud
NAME PROPERTY VALUE
storage/nextcloud recordsize 128K
storage/nextcloud compression lz4
storage/nextcloud compressratio 1.03xUne modification d’un seul octet dans un énorme fichier retient donc un bloc de 128 Ko, là où rdiff-backup aurait peut-être stocké quelques centaines d’octets. Plus grossier, sans discussion.
Ce que ZFS offre en échange :
- Pas de surcoût de miroir. L’état le plus récent de rdiff-backup est une seconde copie complète de tout. Les snapshots partagent chaque bloc inchangé avec les données vivantes – il n’y a aucune base dupliquée.
- Pas de comptabilité par version. Trente snapshots d’un dataset inchangé coûtent trente fois rien.
- lz4 partout, de façon transparente, sur les données vivantes comme sur les snapshots.
Ce compressratio de 1,03x mérite d’être souligné honnêtement : mes données sont des photos et des médias, déjà compressés, donc lz4 ne m’apporte presque rien ici. Ce n’est pas un reproche à lz4 – c’est le résultat correct pour ce contenu, et ce serait très différent sur un dataset rempli de logs ou de texte.
Bilan pour des données mixtes typiques, maison et bureau : comparable en espace, nettement moins coûteux à l’exploitation. Pour le cas particulier de petites modifications fréquentes dans de très gros fichiers, les deltas à l’octet de rdiff-backup restent gagnants en nombre d’octets.
📁 Où vivent les snapshots : le répertoire qui n’existe pas
Les snapshots ne sont pas des fichiers que l’on peut ouvrir dans un gestionnaire de fichiers. Mais ZFS vous offre une fenêtre qui se comporte comme un répertoire ordinaire :
$ ls /storage/nextcloud/.zfs/snapshot/
auto-2026-09-11_1250Le piège dans lequel tout le monde tombe exactement une fois : .zfs est masqué par défaut et n’apparaît pas dans ls -la. Ce n’est pas une entrée de répertoire normale, elle est synthétique. Tapez quand même le chemin, et ça marche.
$ zfs get snapdir storage/nextcloud
NAME PROPERTY VALUE SOURCE
storage/nextcloud snapdir hidden defaultTout ce qui se trouve là-dessous est en lecture seule. Vous ne pouvez pas endommager un snapshot en le parcourant, ni écrire dedans par accident. Vous pouvez seulement copier vers l’extérieur – exactement ce qu’il vous faut lors d’une restauration.
⏱️ Le script, et pourquoi des timers systemd cette fois
Dans l’article sur le scrub et le trim, j’avais découvert que Debian planifie la maintenance ZFS via /etc/cron.d/zfsutils-linux, les timers systemd étant livrés mais désactivés. Pour les snapshots, j’ai délibérément pris le chemin inverse :
[Timer]
OnCalendar=daily
RandomizedDelaySec=15m
Persistent=truePersistent=true en est la raison. Si le NAS est éteint à minuit, cron saute tout simplement ce jour-là sans prévenir personne. systemd exécute la tâche manquée au prochain démarrage. Pour quelque chose dont toute la valeur consiste à exister avant qu’on en ait besoin, sauter des jours en silence n’est pas un mode de défaillance acceptable – et je venais de consacrer un article entier à des choses qui échouent en silence.
RandomizedDelaySec échelonne les quatre datasets pour qu’ils ne se déclenchent pas tous à la même seconde.
Le script de rotation a une seule mission : prendre un snapshot, puis supprimer les plus anciens jusqu’au nombre de rétention.
#!/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"
doneTrois garde-fous avant toute suppression, et ce n’est pas du théâtre paranoïaque. zfs destroy accepte un nom de snapshot et un nom de dataset exactement à la même position d’argument. Si $snap était un jour vide ou tronqué, zfs destroy storage/user3 emporterait 1,17 To de photos de famille sans poser la moindre question. La vérification du @ rend cela structurellement impossible.
Le filtre de préfixe compte aussi : seuls les snapshots créés par ce script peuvent être supprimés. Tout ce qui a été pris à la main, ou par un autre outil, lui est invisible.
🧪 Tester le chemin de suppression, parce qu’évidemment on teste le chemin de suppression
Un zfs destroy non testé dans un timer nocturne pointé sur vos propres données, ce n’est pas le genre de chose qu’on veut découvrir au pire moment. Avant de lui faire confiance, j’ai donc lancé la rotation sur le plus petit dataset avec KEEP=1, pour l’obliger à supprimer réellement quelque chose :
--- 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.4GAncien snapshot disparu, nouveau conservé, dataset intact. Vérifié plutôt que supposé.
Une limite rencontrée pendant les tests et que j’ai décidé de garder : les noms contiennent %H%M, donc deux exécutions dans la même minute entrent en collision avec « dataset already exists ». Sans importance pour un timer quotidien, une énigme de deux secondes pour qui teste à la main. Maintenant, vous savez.
🦠 L’angle ransomware, là où tout cela paie vraiment
Plusieurs personnes synchronisent avec mon Nextcloud via le client de bureau Windows – celui qui monte le cloud comme un lecteur dans l’Explorateur. C’est pratique, et cela signifie aussi que la fiche de poste du client tient en une ligne : « repérer les fichiers modifiés, les envoyer ». Un ransomware sur une telle machine chiffre les fichiers locaux, et le client fait consciencieusement ce pour quoi il a été conçu.
C’est le scénario où la différence entre un miroir et un historique versionné cesse d’être académique. Un simple miroir reproduit fidèlement l’état chiffré. Un historique versionné vous permet de remonter plus loin dans le temps.
L’ordre de restauration qui fonctionne vraiment :
D’abord, arrêter la synchronisation. Déconnectez le client concerné ou passez Nextcloud en mode maintenance. Restaurer dans une relation de synchronisation active avec un poste infecté, c’est juste faire rechiffrer votre restauration – et vous aurez perdu du temps en prime.
Ensuite, essayer les couches propres à Nextcloud. La corbeille côté serveur et le versionnage des fichiers sont de loin la voie la moins coûteuse, et pour tout ce qui n’est pas un incident massif, ils suffisent généralement à eux seuls.
Puis passer aux snapshots. Et ici, une seule distinction compte :
zfs rollbackréinitialise le dataset sur place et détruit irréversiblement tout ce qui est plus récent, y compris les snapshots plus récents. Si vous vous trompez de moment, votre deuxième tentative a disparu.- Copier depuis
.zfs/snapshot/<name>/ne modifie absolument rien. Faites-le dix fois, comparez les résultats, prenez votre temps.
Utilisez la seconde méthode. Le rollback est un outil tranchant pour un autre usage.
Vous n’avez pas non plus à deviner quand les dégâts ont commencé, ce qui était mon premier réflexe. ZFS vous le dit :
$ zfs diff storage/nextcloud@auto-2026-09-10_0000 \
storage/nextcloud@auto-2026-09-11_0000Le snapshot dans lequel des milliers de fichiers apparaissent soudain comme modifiés est celui d’après l’incident. Prenez celui d’avant.
📤 Là où rdiff-backup garde l’avantage, et ce n’est pas rien
Les snapshots vivent dans le pool. Mêmes trois disques, même destin. Le RAIDZ1 survit à un disque mort ; il ne survit ni à un incendie, ni à un vol, ni à un contrôleur qui emporte la grappe avec lui, ni à quelqu’un ayant les droits root qui lance zfs destroy.
Les snapshots protègent donc contre les dommages logiques – ransomware, suppression par erreur de frappe, synchronisation qui a mal tourné. Ils ne font rien contre la perte physique. C’est la moitié que rdiff-backup a toujours bien couverte, en écrivant via SSH sur un matériel entièrement séparé.
ZFS a sa propre réponse ici, et elle s’intègre joliment :
$ 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 n’envoie ensuite que le delta entre deux snapshots, ce qui rend le « disque externe qui vit dans un tiroir » praticable plutôt qu’un projet de week-end.
Ma conclusion n’est pas « remplacer rdiff-backup ». C’est que ces outils n’ont jamais vraiment été en concurrence :
- Les snapshots – un historique instantané, gratuit et illimité contre les dommages logiques, là où se trouvent les données
- Une copie sur un matériel séparé – la seule chose qui survit à la perte de la machine elle-même
🔧 Les commandes qui valent vraiment d’être retenues
Inspection :
$ 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 workParcourir et restaurer :
$ 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/Opérations manuelles :
$ zfs snapshot storage/user3@before-something-risky
$ zfs destroy storage/user3@before-something-risky
$ zfs hold keep storage/user3@important # protect from deletionzfs hold est sous-estimé. Il fait qu’un snapshot refuse d’être supprimé tant que vous ne l’avez pas explicitement libéré – idéal pour l’état connu comme sain que vous voulez voir survivre à toute logique de rotation, y compris la vôtre.
⚠️ Deux choses à savoir avant de compter dessus
La rétention est une vraie limite. Trente jours ici. Un incident passé inaperçu plus longtemps sort de la fenêtre par rotation. Confortable pour un système utilisé activement ; pour des archives froides, ajoutez un niveau mensuel plutôt que d’espérer.
Les snapshots suivent les datasets, pas les répertoires. Celle-là m’a eu en vérifiant mon propre travail. /storage contient quatre datasets – et un simple répertoire qui n’est pas un dataset et qui, par conséquent, ne reçoit discrètement rien du tout :
$ zfs list /storage/gitlab-migration
NAME USED AVAIL REFER MOUNTPOINT
storage 1.78T 1.73T 160K /storageIl a été résolu comme le dataset parent, pas comme lui-même. Faites un mkdir /storage/something demain, et il n’hérite d’aucune politique de snapshot, sans le moindre avertissement. Utilisez plutôt zfs create storage/something, et il obtient tout ce qui lui est propre – snapshots, quotas, propriétés. Cela ne coûte rien, et c’est la différence entre une protection que vous avez et une protection que vous supposez avoir.
Ce qu’il faut vraiment en retenir
Ce qui m’a le plus frappé en faisant tout cela, ce n’est ni l’efficacité en espace ni même la vitesse. C’est l’endroit où le travail se fait.
rdiff-backup, comme presque tous les outils de sauvegarde, doit aller découvrir ce qui a changé – parcourir des arborescences, comparer, calculer. C’est un effort énorme pour redécouvrir quelque chose que le système de fichiers a vu se produire en temps réel, puis oublié.
ZFS n’oublie pas. Le copy-on-write signifie que l’information était déjà là ; un snapshot se contente de refuser de la jeter. C’est pour cela qu’il est instantané, et c’est pour cela qu’il ne coûte rien tant que rien ne change réellement.
Un bon rappel que la question intéressante en matière d’infrastructure n’est généralement pas « quel outil est le meilleur ? », mais « qui connaît déjà la réponse, et est-ce que je la lui demande – ou est-ce que je la recalcule chaque nuit à 3 h du matin ? »




