Sauvegarder un serveur Linux avec Restic : la règle 3-2-1
Snapshots chiffrés, dédupliqués, envoyés hors site : mettre en place des sauvegardes Restic automatiques, et surtout tester la restauration.
Un serveur self-hosted tourne des mois sans incident. Puis un disque meurt, une mise à jour corrompt une base, ou une commande tapée trop vite efface le mauvais dossier. Ce jour-là, une seule question compte : quand date la dernière sauvegarde, et est-ce qu'elle se restaure ?
Beaucoup de gens découvrent la réponse à ce moment-là. C'est le pire moment.
Restic est un outil de sauvegarde open-source en ligne de commande. Il découpe les fichiers en blocs, ne stocke chaque bloc qu'une fois (déduplication), chiffre tout côté client et envoie le résultat vers un disque local, un serveur SFTP ou un stockage objet compatible S3. Chaque sauvegarde devient un snapshot qu'on peut parcourir et restaurer indépendamment.
La règle 3-2-1
Avant l'outil, la stratégie. La règle 3-2-1 est le standard depuis des décennies :
- 3 copies des données (l'original + 2 sauvegardes)
- sur 2 supports différents
- dont 1 hors site
Un RAID n'est pas une sauvegarde : il protège contre la panne d'un disque, pas contre une suppression, un ransomware ou une base corrompue, qui sont répliqués instantanément sur tous les disques. Un snapshot sur le même serveur non plus : si la machine brûle ou si l'hébergeur ferme le compte, tout part avec.
Dans la pratique, pour un serveur perso :
| Copie | Où | Protège contre |
|---|---|---|
| Original | Le serveur | — |
| Sauvegarde 1 | Un autre disque ou un NAS à la maison | Erreur humaine, corruption, panne disque |
| Sauvegarde 2 | Un stockage cloud (Backblaze B2, S3, Hetzner Storage Box) | Incendie, vol, perte du serveur entier |
Pourquoi Restic
J'ai utilisé rsync, puis Borg, avant de m'arrêter sur Restic. Ce qui fait la différence :
- Chiffrement obligatoire. Le fournisseur cloud ne voit que des blocs illisibles. Impossible de l'oublier.
- Déduplication. Seuls les blocs modifiés sont envoyés. Trente snapshots quotidiens d'un serveur de 50 Go occupent rarement beaucoup plus que 50 Go.
- Backends natifs. SFTP, S3, Backblaze B2, Azure, Google Cloud, et des dizaines d'autres via rclone.
- Un seul binaire. Pas de démon, pas de serveur à installer côté destination.
Borg est un excellent concurrent, un peu plus rapide, mais il exige Borg installé des deux côtés. Restic écrit directement dans un bucket S3, ce qui simplifie la copie hors site.
Installation et premier dépôt
sudo apt install restic
sudo restic self-update # la version des dépôts Debian/Ubuntu est souvent ancienneRestic travaille avec un dépôt (repository) : l'endroit où sont stockés les snapshots. On le crée une fois.
Pour éviter de répéter les paramètres, on les met dans un fichier d'environnement lisible uniquement par root :
RESTIC_REPOSITORY=s3:https://s3.eu-central-003.backblazeb2.com/mon-bucket-backup
RESTIC_PASSWORD_FILE=/etc/restic/password
AWS_ACCESS_KEY_ID=xxxxxxxxxxxx
AWS_SECRET_ACCESS_KEY=xxxxxxxxxxxxsudo mkdir -p /etc/restic
openssl rand -base64 32 | sudo tee /etc/restic/password > /dev/null
sudo chmod 600 /etc/restic/password /etc/restic/env
# Charger les variables puis initialiser le dépôt
set -a; source /etc/restic/env; set +a
restic initCopiez immédiatement le mot de passe dans votre gestionnaire de mots de passe. Sans lui, les sauvegardes sont définitivement illisibles, y compris par vous. Un mot de passe stocké uniquement sur le serveur qu'on sauvegarde disparaît avec lui.
Pour un dépôt sur un autre serveur en SFTP, seule la ligne du dépôt change :
RESTIC_REPOSITORY=sftp:backup@nas.local:/srv/restic/monserveurQue sauvegarder
Sur un serveur qui fait tourner des applications avec Docker Compose, la liste est courte :
/srv/ ← dossiers des stacks : compose.yaml, .env, bind mounts
/etc/ ← configuration système (Caddy, Nginx, cron…)
/home/ ← fichiers utilisateurs
/var/lib/docker/volumes/ ← volumes nommés (avec précaution, voir plus bas)Les images Docker, les paquets système et /var/cache ne servent à rien : ils se retéléchargent.
On exclut le superflu dans un fichier :
**/node_modules
**/.cache
**/cache
**/*.tmp
/var/lib/docker/volumes/*/_data/**/logsLe piège des bases de données
Copier les fichiers d'une base PostgreSQL ou MySQL pendant qu'elle tourne produit souvent une sauvegarde incohérente : une partie des fichiers date d'avant une écriture, une autre d'après. La restauration peut refuser de démarrer.
La bonne méthode : exporter la base dans un fichier SQL juste avant la sauvegarde, et sauvegarder ce fichier.
docker compose -f /srv/app/compose.yaml exec -T db \
pg_dump -U app app | gzip > /srv/dumps/app-$(date +%F).sql.gzpg_dump produit un instantané cohérent même pendant que la base reçoit des écritures. Les commandes et options de restauration sont détaillées dans les bases de PostgreSQL. Pour MySQL ou MariaDB, l'équivalent est mysqldump --single-transaction.
C'est exactement ce que font des applications comme Nextcloud ou Immich : fichiers d'un côté, base de l'autre, et c'est la base qui casse si on la copie à chaud.
Le script de sauvegarde
On rassemble tout dans un script :
#!/usr/bin/env bash
set -euo pipefail
set -a; source /etc/restic/env; set +a
# 1. Exporter les bases de données
mkdir -p /srv/dumps
docker compose -f /srv/app/compose.yaml exec -T db \
pg_dump -U app app | gzip > /srv/dumps/app.sql.gz
# 2. Sauvegarder
restic backup /srv /etc /home \
--exclude-file /etc/restic/excludes \
--tag auto
# 3. Appliquer la politique de rétention et libérer l'espace
restic forget --tag auto \
--keep-daily 7 --keep-weekly 4 --keep-monthly 12 \
--prune
# 4. Vérifier l'intégrité d'un échantillon des données
restic check --read-data-subset=5%sudo chmod 700 /usr/local/bin/backup.sh
sudo /usr/local/bin/backup.shLa politique forget garde un snapshot par jour sur une semaine, un par semaine sur un mois, un par mois sur un an. Environ 23 snapshots au total, qui couvrent un an d'historique. --prune supprime réellement les blocs qui ne sont plus utilisés par aucun snapshot.
check --read-data-subset=5% relit 5 % des données à chaque passage. En trois semaines, l'ensemble du dépôt a été vérifié sans jamais tout télécharger d'un coup.
Automatiser avec un timer systemd
Cron fonctionne, mais un timer systemd garde les logs dans le journal et rattrape une exécution manquée si le serveur était éteint.
[Unit]
Description=Sauvegarde Restic
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh[Unit]
Description=Sauvegarde Restic quotidienne
[Timer]
OnCalendar=*-*-* 03:30:00
Persistent=true
RandomizedDelaySec=15m
[Install]
WantedBy=timers.targetsudo systemctl daemon-reload
sudo systemctl enable --now backup.timer
systemctl list-timers backup.timer # prochaine exécution
journalctl -u backup.service -n 50 # logs de la dernière sauvegardeÊtre prévenu quand ça échoue
Une sauvegarde qui échoue en silence depuis trois mois est pire qu'aucune sauvegarde : on se croit protégé. Il faut une alerte.
Le plus simple : envoyer une notification à la fin du script, en cas de succès comme d'échec. Avec ntfy et ses notifications push en une requête curl, il suffit d'ajouter un trap en haut du script :
trap 'curl -s -d "Sauvegarde ÉCHOUÉE sur $(hostname)" ntfy.sh/mon-topic-secret' ERREt une ligne à la fin, après le check :
curl -s -d "Sauvegarde OK sur $(hostname)" ntfy.sh/mon-topic-secretMieux encore : un service de monitoring qui s'alarme quand il ne reçoit pas de signal. Une sauvegarde qui ne démarre plus du tout ne déclenche aucun trap. Uptime Kuma (moniteur de type « Push ») ou Healthchecks.io font exactement ça.
Restaurer : la seule étape qui compte
Une sauvegarde jamais restaurée est une hypothèse. Voici les commandes à connaître avant d'en avoir besoin :
set -a; source /etc/restic/env; set +a
restic snapshots # lister les snapshots
restic ls latest /srv/app # parcourir le dernier snapshot
# Restaurer un dossier dans un emplacement temporaire
restic restore latest --target /tmp/restore --include /srv/app
# Restaurer un fichier précis depuis un snapshot donné
restic restore 4f3a9c2e --target /tmp/restore --include /etc/caddy/Caddyfile
# Monter tous les snapshots comme un dossier navigable
mkdir -p /mnt/restic && restic mount /mnt/resticNe restaurez jamais directement par-dessus les données en place. Restaurez dans /tmp/restore, vérifiez, puis copiez.
Je fais un test de restauration complet tous les trois mois, sur une machine de test ou un petit VPS loué pour une heure :
- installer Docker et Restic ;
- restaurer
/srvet le dump SQL ; - réimporter la base ;
docker compose up -d;- vérifier que l'application fonctionne et que les données récentes sont là.
La première fois, ce test révèle presque toujours un oubli : un fichier .env exclu, un volume non sauvegardé, un mot de passe introuvable. Mieux vaut le découvrir un dimanche tranquille que le jour de la panne.
Combien ça coûte
Pour 100 Go de données dédupliquées, en ordre de grandeur :
| Destination | Coût mensuel indicatif |
|---|---|
| Disque USB ou NAS existant | Gratuit |
| Backblaze B2 | Environ 0,60 € |
| Hetzner Storage Box (1 To) | Environ 4 € |
| AWS S3 Standard | Environ 2,30 € |
Les tarifs évoluent : vérifiez la page de prix du fournisseur avant de choisir. Méfiez-vous surtout des frais de sortie (egress) : certains fournisseurs facturent cher le téléchargement des données, donc la restauration.
Combien de temps faut-il pour mettre en place une vraie sauvegarde 3-2-1 avec Restic ? Une heure, test de restauration compris. C'est l'heure la plus rentable qu'on puisse passer sur un serveur. Le reste (choix des applications, optimisation, monitoring) se rattrape toujours. Des données perdues, jamais.