Stratégies de sauvegarde Linux : la règle 3-2-1 en pratique

Guide complet pour mettre en place une stratégie de sauvegarde robuste sur serveur Linux avec rsync, rsnapshot, borgbackup et automatisation cron.

Les sauvegardes, c'est un peu comme l'assurance habitation : personne n'y pense sérieusement jusqu'au jour où le disque dur lâche à 3h du matin, où une mise à jour foireuse corrompt la base de données, ou pire, où un ransomware chiffre l'intégralité du serveur de production. Ce jour-là, la question n'est plus « est-ce que j'ai un backup ? » mais « est-ce que mon backup est exploitable ? ». Spoiler : dans beaucoup de cas, la réponse est non.

Cet article pose les bases d'une stratégie de sauvegarde solide pour serveurs commandes Linux, en partant de la règle 3-2-1 et en descendant jusqu'aux commandes concrètes. Pas de théorie creuse : du code, des fichiers de configuration, et des pratiques éprouvées en production.

Comprendre la règle 3-2-1

La règle 3-2-1 est le socle de toute stratégie de sauvegarde sérieuse. Le principe est simple :

  • 3 copies de vos données (l'original + 2 sauvegardes)
  • 2 supports différents (disque local + NAS, ou SSD + bande magnétique)
  • 1 copie hors site (un autre datacenter, un serveur distant, ou du stockage objet type S3)

L'idée derrière cette règle est de se protéger contre les différents types de sinistres. Un disque dur peut mourir, mais il est statistiquement improbable que deux disques sur deux supports différents meurent en même temps. Et si votre salle serveur brûle, la copie hors site vous sauve.

Un backup qui n'existe que sur le même disque que les données originales n'est pas un backup. C'est une illusion de sécurité.

En pratique, voici un exemple d'architecture 3-2-1 pour un serveur web classique :

  • Copie 1 : les données live sur le serveur (disque SSD)
  • Copie 2 : sauvegarde quotidienne vers un NAS local via rsync
  • Copie 3 : sauvegarde hebdomadaire chiffrée vers un serveur distant via borgbackup

rsync : la base de toute stratégie

rsync est l'outil fondamental de la sauvegarde sous Linux. Il synchronise des fichiers de manière incrémentale en ne transférant que les différences, ce qui le rend rapide et économe en bande passante.

Les options essentielles

# Sauvegarde locale basique
rsync -avz --delete /var/www/ /mnt/backup/www/

# Sauvegarde distante via SSH
rsync -avz --delete -e "ssh -p 22" /var/www/ user@backup-server:/backup/www/

# Avec exclusions (logs, cache, fichiers temporaires)
rsync -avz --delete \
    --exclude='*.log' \
    --exclude='.cache/' \
    --exclude='tmp/' \
    /var/www/ /mnt/backup/www/

Décortiquons les options les plus importantes :

  • -a (archive) : préserve les permissions, propriétaires, dates, liens symboliques
  • -v (verbose) : affiche les fichiers transférés
  • -z (compress) : compresse les données pendant le transfert
  • --delete : supprime sur la destination les fichiers qui n'existent plus sur la source
  • --dry-run : simule l'opération sans rien modifier (indispensable pour tester)

Script de sauvegarde rsync robuste

#!/bin/bash
# backup-rsync.sh - Sauvegarde quotidienne avec rsync
set -euo pipefail

BACKUP_SRC="/var/www /etc /home"
BACKUP_DST="/mnt/nas/backups/$(hostname)"
LOG_FILE="/var/log/backup-rsync.log"
DATE=$(date +%Y-%m-%d_%H%M)

exec >> "$LOG_FILE" 2>&1
echo "=== Début sauvegarde : $DATE ==="

for src in $BACKUP_SRC; do
    dir_name=$(basename "$src")
    mkdir -p "${BACKUP_DST}/${dir_name}"

    rsync -avz --delete \
        --exclude='*.log' \
        --exclude='*.tmp' \
        --exclude='.cache/' \
        "$src/" "${BACKUP_DST}/${dir_name}/"

    echo "[OK] $src sauvegardé"
done

echo "=== Fin sauvegarde : $(date +%Y-%m-%d_%H%M) ==="

L'option set -euo pipefail est cruciale : elle fait échouer le script à la première erreur au lieu de continuer silencieusement. Un script de backup qui échoue sans prévenir est pire qu'un script qui n'existe pas.

Sauvegardes incrémentales avec rsnapshot

rsnapshot pousse le concept de rsync plus loin en gérant automatiquement la rotation et la rétention des sauvegardes via des hard links. Résultat : chaque snapshot ressemble à une copie complète, mais ne consomme que l'espace des fichiers modifiés.

Installation et configuration

# Installation
sudo apt install rsnapshot    # Debian/Ubuntu
sudo dnf install rsnapshot    # Fedora/RHEL

# Fichier de configuration principal
sudo nano /etc/rsnapshot.conf

Attention : rsnapshot utilise des tabulations comme séparateurs dans son fichier de configuration, pas des espaces. C'est la source d'erreur numéro un.

# /etc/rsnapshot.conf (séparateurs = tabulations !)
config_version	1.2
snapshot_root	/mnt/backup/rsnapshot/
cmd_cp	/bin/cp
cmd_rm	/bin/rm
cmd_rsync	/usr/bin/rsync
cmd_ssh	/usr/bin/ssh
cmd_logger	/usr/bin/logger

# Niveaux de rétention
retain	hourly	6
retain	daily	7
retain	weekly	4
retain	monthly	6

# Répertoires à sauvegarder
backup	/var/www/	localhost/
backup	/etc/	localhost/
backup	/home/	localhost/

# Serveur distant via SSH
backup	user@serveur-distant:/var/www/	distant/

Planification avec cron

# /etc/cron.d/rsnapshot
0 */4 * * *    root    /usr/bin/rsnapshot hourly
30 3  * * *    root    /usr/bin/rsnapshot daily
0  3  * * 1    root    /usr/bin/rsnapshot weekly
30 2  1 * *    root    /usr/bin/rsnapshot monthly

Vérifiez toujours votre configuration avant de lancer :

# Test de la configuration (ne fait rien, vérifie la syntaxe)
rsnapshot configtest

# Simulation d'une sauvegarde hourly
rsnapshot -t hourly

Sauvegarder les bases de données

Copier les fichiers d'une base de données en cours d'exécution est une très mauvaise idée. Les fichiers peuvent être dans un état incohérent. Il faut impérativement utiliser les outils de dump fournis par le SGBD.

MySQL / MariaDB

#!/bin/bash
# backup-mysql.sh
set -euo pipefail

BACKUP_DIR="/mnt/backup/mysql"
DATE=$(date +%Y-%m-%d)
RETENTION_DAYS=30

mkdir -p "$BACKUP_DIR"

# Dump de toutes les bases
mysqldump --all-databases \
    --single-transaction \
    --routines \
    --triggers \
    --events \
    --quick \
    | gzip > "${BACKUP_DIR}/all-databases_${DATE}.sql.gz"

# Suppression des anciens dumps
find "$BACKUP_DIR" -name "*.sql.gz" -mtime +${RETENTION_DAYS} -delete

echo "[OK] Dump MySQL terminé : $(du -h ${BACKUP_DIR}/all-databases_${DATE}.sql.gz)"

L'option --single-transaction est essentielle pour les tables InnoDB : elle garantit un dump cohérent sans verrouiller les tables.

PostgreSQL

#!/bin/bash
# backup-postgresql.sh
set -euo pipefail

BACKUP_DIR="/mnt/backup/postgresql"
DATE=$(date +%Y-%m-%d)

mkdir -p "$BACKUP_DIR"

# Dump de toutes les bases avec rôles et tablespaces
pg_dumpall --clean \
    | gzip > "${BACKUP_DIR}/pg_dumpall_${DATE}.sql.gz"

# Alternative : dump base par base en format custom (restauration sélective)
for db in $(psql -t -c "SELECT datname FROM pg_database WHERE datistemplate = false;"); do
    pg_dump -Fc "$db" > "${BACKUP_DIR}/${db}_${DATE}.dump"
done

echo "[OK] Dump PostgreSQL terminé"

Le format custom (-Fc) de pg_dump permet une restauration sélective de tables individuelles, ce qui est précieux quand on ne veut restaurer qu'une partie de la base.

Chiffrement et sécurité des sauvegardes

Une sauvegarde non chiffrée sur un serveur distant est un risque de sécurité majeur. Si le serveur de backup est compromis, toutes vos données le sont aussi. Deux approches complémentaires existent.

Chiffrement avec GPG

# Chiffrer un dump de base de données
gpg --symmetric --cipher-algo AES256 \
    --output backup_2026-02-08.sql.gz.gpg \
    backup_2026-02-08.sql.gz

# Déchiffrer
gpg --decrypt backup_2026-02-08.sql.gz.gpg > backup_2026-02-08.sql.gz

# Dans un script automatisé (passphrase via fichier sécurisé)
gpg --batch --yes --passphrase-file /root/.backup-passphrase \
    --symmetric --cipher-algo AES256 \
    --output "${BACKUP_DIR}/dump_${DATE}.sql.gz.gpg" \
    "${BACKUP_DIR}/dump_${DATE}.sql.gz"

Le fichier de passphrase doit avoir des permissions strictes : chmod 600 /root/.backup-passphrase.

borgbackup : la solution tout-en-un

borgbackup combine déduplication, compression et chiffrement. C'est l'outil idéal pour les sauvegardes hors site car il minimise la bande passante et l'espace disque utilisés.

# Initialiser un dépôt chiffré
borg init --encryption=repokey user@backup-srv:/backup/borg-repo

# Créer une sauvegarde
borg create --stats --progress \
    --compression zstd,6 \
    user@backup-srv:/backup/borg-repo::{hostname}-{now:%Y-%m-%d_%H%M} \
    /var/www /etc /home \
    --exclude '*.log' \
    --exclude '.cache'

# Politique de rétention automatique
borg prune --stats \
    --keep-daily=7 \
    --keep-weekly=4 \
    --keep-monthly=12 \
    user@backup-srv:/backup/borg-repo

restic : l'alternative moderne

# Initialiser un dépôt (supporte S3, SFTP, local, etc.)
restic -r sftp:user@backup-srv:/backup/restic-repo init

# Sauvegarder
restic -r sftp:user@backup-srv:/backup/restic-repo backup \
    /var/www /etc /home \
    --exclude="*.log" \
    --exclude=".cache"

# Vérifier l'intégrité
restic -r sftp:user@backup-srv:/backup/restic-repo check

restic a l'avantage de supporter nativement de nombreux backends de stockage (S3, Azure Blob, Google Cloud Storage, SFTP) sans configuration supplémentaire.

Automatisation et planification

Un backup manuel est un backup oublié. L'automatisation est non négociable.

Cron : la méthode classique

# /etc/cron.d/backup-strategy
# Dump bases de données tous les jours à 2h00
0  2 * * *    root    /opt/scripts/backup-mysql.sh
# rsync vers NAS tous les jours à 3h00
0  3 * * *    root    /opt/scripts/backup-rsync.sh
# borg vers serveur distant tous les dimanches à 4h00
0  4 * * 0    root    /opt/scripts/backup-borg.sh

systemd timers : la méthode moderne

Les timers systemd offrent plusieurs avantages par rapport à cron : journalisation intégrée, gestion des dépendances, et exécution des tâches ratées au prochain démarrage.

# /etc/systemd/system/backup-daily.service
[Unit]
Description=Sauvegarde quotidienne
After=network-online.target

[Service]
Type=oneshot
ExecStart=/opt/scripts/backup-rsync.sh
StandardOutput=journal
StandardError=journal

# /etc/systemd/system/backup-daily.timer
[Unit]
Description=Planification sauvegarde quotidienne

[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true
RandomizedDelaySec=600

[Install]
WantedBy=timers.target
# Activer le timer
sudo systemctl enable --now backup-daily.timer

# Vérifier le statut
systemctl list-timers --all | grep backup

# Consulter les logs de la dernière exécution
journalctl -u backup-daily.service --since today

L'option Persistent=true est particulièrement utile : si le serveur était éteint au moment prévu, la sauvegarde sera lancée au prochain démarrage. Avec cron, elle serait simplement perdue.

Script wrapper avec notifications

#!/bin/bash
# backup-wrapper.sh - Orchestrateur de sauvegarde avec alertes
set -euo pipefail

LOG_FILE="/var/log/backup-$(date +%Y-%m-%d).log"
ALERT_EMAIL="admin@example.com"
HOSTNAME=$(hostname -f)

exec >> "$LOG_FILE" 2>&1

backup_status=0

echo "=== Début backup complet : $(date) ==="

# Étape 1 : Dump des bases
/opt/scripts/backup-mysql.sh || backup_status=1

# Étape 2 : Synchronisation locale
/opt/scripts/backup-rsync.sh || backup_status=1

# Étape 3 : Sauvegarde chiffrée hors site
/opt/scripts/backup-borg.sh || backup_status=1

echo "=== Fin backup complet : $(date) ==="

# Notification en cas d'échec
if [ $backup_status -ne 0 ]; then
    mail -s "[ALERTE] Échec backup sur ${HOSTNAME}" "$ALERT_EMAIL" < "$LOG_FILE"
    exit 1
fi

Tester ses restaurations

Voici la vérité que personne ne veut entendre : un backup qui n'a jamais été testé en restauration n'est pas un backup. C'est un fichier qui occupe de l'espace disque et qui vous donne un faux sentiment de sécurité.

Procédure de test de restauration

#!/bin/bash
# test-restore.sh - Vérification mensuelle des sauvegardes
set -euo pipefail

RESTORE_DIR="/tmp/restore-test-$(date +%Y%m%d)"
mkdir -p "$RESTORE_DIR"

echo "=== Test de restauration : $(date) ==="

# Test 1 : Restauration fichiers depuis rsnapshot
echo "[TEST] Restauration rsnapshot..."
cp -a /mnt/backup/rsnapshot/daily.0/localhost/var/www/ \
    "${RESTORE_DIR}/www-restore/"
diff -rq /var/www/ "${RESTORE_DIR}/www-restore/" \
    && echo "[OK] Fichiers web intègres" \
    || echo "[ERREUR] Différences détectées"

# Test 2 : Restauration base MySQL
echo "[TEST] Restauration MySQL..."
LATEST_DUMP=$(ls -t /mnt/backup/mysql/all-databases_*.sql.gz | head -1)
gunzip -c "$LATEST_DUMP" | mysql --database=test_restore \
    && echo "[OK] Dump MySQL exploitable" \
    || echo "[ERREUR] Dump MySQL corrompu"

# Test 3 : Vérification intégrité borg
echo "[TEST] Vérification borg..."
borg check user@backup-srv:/backup/borg-repo \
    && echo "[OK] Dépôt borg intègre" \
    || echo "[ERREUR] Dépôt borg corrompu"

# Nettoyage
rm -rf "$RESTORE_DIR"

echo "=== Fin des tests : $(date) ==="

Planifiez ce script une fois par mois. Ajoutez-le dans vos timers systemd ou votre crontab. Le jour où vous aurez besoin d'une restauration réelle, vous saurez exactement que vos sauvegardes fonctionnent.

Points de contrôle essentiels

  • Intégrité : le fichier n'est pas corrompu (checksums, borg check, restic check)
  • Complétude : toutes les données attendues sont présentes
  • Exploitabilité : le dump se restaure effectivement dans une base fonctionnelle
  • Délai : combien de temps prend la restauration complète ? (RTO)
  • Fraîcheur : quelle est la date du dernier backup réussi ? (RPO)

Récapitulatif et mise en place

Voici un résumé de la stratégie complète à mettre en place :

  • Règle 3-2-1 : 3 copies, 2 supports, 1 hors site. Non négociable.
  • Données fichiers : rsync pour la synchronisation, rsnapshot pour la rotation avec rétention.
  • Bases de données : dumps dédiés avec mysqldump ou pg_dump, jamais de copie de fichiers bruts.
  • Chiffrement : borgbackup ou restic pour le hors site, GPG pour les dumps sensibles.
  • Automatisation : systemd timers de préférence, cron en fallback. Notifications d'échec obligatoires.
  • Tests mensuels : restauration effective des données, pas juste une vérification de taille de fichier.

Commencez par le plus simple : un script rsync quotidien vers un second disque. Puis ajoutez progressivement les couches de complexité. Une stratégie de sauvegarde imparfaite mais en place vaut infiniment mieux qu'une stratégie parfaite qui reste dans un document de planification.

Cet article vous a plu ?

Commentaires

Morgann Riu
Morgann Riu

Expert en cybersécurité et administration Linux. J'aide les entreprises à sécuriser et optimiser leurs infrastructures critiques.

Retour au blog

Checklist Sécurité Linux

30 points essentiels pour sécuriser un serveur Linux. Recevez aussi les nouveaux tutoriels par email.

Pas de spam. Désabonnement en 1 clic.