Administration
Linux
Sauvegarde

Backup avec Rsync : Implémenter une Stratégie 3-2-1 sur Linux

16 février 2026

8 min de lecture

Vous avez des données importantes sur un serveur Linux. Vous pensez être couvert parce que vous faites un cp de temps en temps, ou peut-être un tar une fois de semaine. Et puis un jour, le disque lâche. Ou pire — un ransomware chiffre tout, backup inclus, parce que votre backup était sur le même volume. La stratégie 3-2-1, c'est la réponse à ça. Trois copies, deux supports différents, une copie hors site. Rsync est votre outil. Ce guide vous montre comment le mettre en place, du plus simple au plus solide.

Prérequis

  • Linux : Debian, Ubuntu, RHEL, Rocky
  • rsync installé (apt install rsync ou yum install rsync)
  • Accès SSH vers un serveur distant (pour la copie offsite)
  • Un support externe ou un second disque (pour la copie locale)
  • Optionnel : un compte cloud compatible (Backblaze B2, Wasabi) pour l'offsite

La stratégie 3-2-1 : pourquoi ça marche

La règle est simple. Trois copies de vos données. Sur deux types de supports différents. Et une copie hors du même lieu physique.

Par exemple : une copie sur votre disque principal, une sur un disque externe branché au même serveur, une sur un serveur distant via SSH. Si le datacenter brûle, vous avez encore la copie distante. Si le ransomware frappe, il ne peut pas atteindre le serveur SSH distant. C'est la couverture minimale qu'on doit avoir en production.

Rsync : les options qui comptent

Avant d'écrire un script, il faut maîtriser les flags. Pas tous — juste celles qui changent la donne.

rsync -avzP --delete source/ destination/
  • -a : mode archive — préserve les permissions, timestamps, liens symboliques, propriétaires
  • -v : verbose — vous voyez ce qui se passe
  • -z : compression en transit — essentiel pour les sauvegardes distantes
  • -P : reprend les transferts interrompus + affiche la progression
  • --delete : supprime dans la destination ce qui n'existe plus dans la source — votre destination reste un miroir exact
# Exclure des fichiers ou répertoires
rsync -avzP --delete --exclude='*.tmp' --exclude='/var/log/*' source/ dest/

# Limiter la bande passante (utile pour l'offsite)
rsync -avzP --delete --bwlimit=500K source/ dest/

# Dry run — voir ce qui va être fait sans toucher à quoi que ce soit
rsync -avzP --delete -n source/ dest/

Attention : le slash entre source/ et source fait une énorme différence. source/ copie le contenu du répertoire. source copie le répertoire lui-même.

Copie 1 : backup local sur un second disque

C'est votre première ligne de défense. Rapide, pas besoin de réseau.

#!/usr/bin/env bash
set -euo pipefail

# ─── Configuration ───────────────────────────────────────────
readonly SOURCE="/var/www"
readonly DEST="/mnt/backup-local/www"
readonly LOG="/var/log/backup-local.log"
readonly TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')

log()   { echo "[$TIMESTAMP] [INFO]  $*" | tee -a "$LOG"; }
error() { echo "[$TIMESTAMP] [ERROR] $*" | tee -a "$LOG" >&2; }

# ─── Vérifications ──────────────────────────────────────────
main() {
    # Le disque backup monté ?
    if ! mountpoint -q /mnt/backup-local; then
        error "Le disque backup n'est pas monté sur /mnt/backup-local"
        exit 1
    fi

    mkdir -p "$DEST"

    log "Backup local démarré : $SOURCE$DEST"
    if rsync -avzP --delete \
        --exclude='*.tmp' \
        --exclude='*.log' \
        --log-file="$LOG" \
        "$SOURCE/" "$DEST/"; then
        log "Backup local OK"
    else
        error "Backup local échoué"
        exit 1
    fi
}

main "$@"

Copie 2 : backup vers un serveur distant via SSH

C'est votre copie offsite. Elle sort physiquement de votre datacenter.

#!/usr/bin/env bash
set -euo pipefail

# ─── Configuration ───────────────────────────────────────────
readonly SOURCE="/var/www"
readonly REMOTE_USER="backup"
readonly REMOTE_HOST="backup.exemple.com"
readonly REMOTE_DEST="/var/backups/www"
readonly LOG="/var/log/backup-distant.log"
readonly TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
readonly BWLIMIT="2M"  # 2 Mo/s max

log()   { echo "[$TIMESTAMP] [INFO]  $*" | tee -a "$LOG"; }
error() { echo "[$TIMESTAMP] [ERROR] $*" | tee -a "$LOG" >&2; }

main() {
    log "Backup distant démarré : $SOURCE${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_DEST}"

    if rsync -avzP --delete \
        --bwlimit="$BWLIMIT" \
        --exclude='*.tmp' \
        --exclude='*.log' \
        -e "ssh -i /root/.ssh/id_ed25519_backup -o StrictHostKeyChecking=yes" \
        --log-file="$LOG" \
        "$SOURCE/" "${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_DEST}/"; then
        log "Backup distant OK"
    else
        error "Backup distant échoué"
        exit 1
    fi
}

main "$@"
Configurer l'utilisateur backup côté serveur distant

L'utilisateur backup ne doit avoir qu'un accès minimal — pas de shell, juste rsync.

# Sur le serveur distant
sudo useradd -r -s /usr/sbin/nologin backup
sudo mkdir -p /var/backups/www
sudo chown backup:backup /var/backups/www

# Copier la clé SSH publique
sudo mkdir -p /home/backup/.ssh
sudo cp /chemin/vers/id_ed25519_backup.pub /home/backup/.ssh/authorized_keys
sudo chown -R backup:backup /home/backup/.ssh
sudo chmod 700 /home/backup/.ssh
sudo chmod 600 /home/backup/.ssh/authorized_keys

Copie 3 : backup vers le cloud (offsite ultime)

Si vous voulez une troisième couche vraiment indépendante, Backblaze B2 est le meilleur rapport prix/fiabilité. Rclone fait le job.

# Installation de rclone
curl https://rclone.org/install.sh | sudo bash

# Configuration pour Backblaze B2
rclone config
# → Suivez l'assistant : choisissez "b2", entrez votre Application Key ID + Key

# Sync vers B2
rclone sync /var/backups/local b2:votre-bucket/backups --log-level INFO
# Script d'automatisation
#!/usr/bin/env bash
set -euo pipefail

readonly SOURCE="/var/backups/local"
readonly DEST="b2:votre-bucket/backups"
readonly LOG="/var/log/backup-cloud.log"

log()   { echo "[$(date '+%Y-%m-%d %H:%M:%S')] [INFO]  $*" | tee -a "$LOG"; }
error() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] [ERROR] $*" | tee -a "$LOG" >&2; }

main() {
    log "Sync cloud démarré"
    if rclone sync "$SOURCE" "$DEST" --log-level INFO --log-file="$LOG"; then
        log "Sync cloud OK"
    else
        error "Sync cloud échoué"
        exit 1
    fi
}

main "$@"

Backup d'une base de données : dump avant rsync

Rsync copie des fichiers. Une base de données en cours d'écriture, vous ne la copiez pas comme ça — vous la dump d'abord.

#!/usr/bin/env bash
set -euo pipefail

readonly DB_NAME="myapp"
readonly DB_USER="backup_user"
readonly DUMP_DIR="/var/backups/db"
readonly RETENTION_DAYS=7
readonly TIMESTAMP=$(date '+%Y%m%d_%H%M%S')
readonly LOG="/var/log/backup-db.log"

log()   { echo "[$(date '+%Y-%m-%d %H:%M:%S')] [INFO]  $*" | tee -a "$LOG"; }
error() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] [ERROR] $*" | tee -a "$LOG" >&2; }

main() {
    mkdir -p "$DUMP_DIR"
    local dump_file="${DUMP_DIR}/${DB_NAME}_${TIMESTAMP}.sql.gz"

    log "Dump PostgreSQL : $DB_NAME"
    if pg_dump -U "$DB_USER" -d "$DB_NAME" -Fc -Z 6 -f "$dump_file"; then
        log "Dump OK : $dump_file ($(du -h "$dump_file" | cut -f1))"
    else
        error "Dump échoué pour $DB_NAME"
        exit 1
    fi

    # Vérification intégrité du dump
    if ! pg_restore --list "$dump_file" >/dev/null 2>&1; then
        error "Dump corrompu : $dump_file"
        rm -f "$dump_file"
        exit 1
    fi
    log "Intégrité vérifié OK"

    # Nettoyage ancien dumps
    find "$DUMP_DIR" -name "*.sql.gz" -mtime +"$RETENTION_DAYS" -delete
    log "Nettoyage terminé"

    # Le dump est maintenant dans /var/backups/db — rsync le copiera automatiquement
}

main "$@"

Automatisation avec cron

# /etc/cron.d/backup-321

# Backup local — toutes les 6 heures
0 */6 * * * root /opt/scripts/backup-local.sh

# Dump DB — quotidien à 1h
0 1 * * * root /opt/scripts/backup-db.sh

# Backup distant — quotidien à 2h (après le dump)
0 2 * * * root /opt/scripts/backup-distant.sh

# Sync cloud — quotidien à 3h
0 3 * * * root /opt/scripts/backup-cloud.sh

Restauration : tester avant que ça arrive

Un backup qui n'a jamais été testé n'existe pas vraiment. Testez régulièrement.

# Restaurer depuis le backup local vers un répertoire temporaire
rsync -avP /mnt/backup-local/www/ /tmp/restore-test/

# Vérifier que les fichiers sont intègres
diff -rq /var/www /tmp/restore-test/

# Restaurer un dump PostgreSQL
pg_restore -U postgres -d myapp_test --clean /var/backups/db/myapp_20260203_020000.sql.gz

# Nettoyer
rm -rf /tmp/restore-test

Tableau récapitulatif — votre 3-2-1

CopieDestinationFréquenceOutilRétention
1Disque local secondaireToutes les 6hrsyncMiroir live
2Serveur SSH distantQuotidien (2h)rsync over SSH30 jours
3Cloud (B2/Wasabi)Quotidien (3h)rclone90 jours

Pièges classiques

Le piège numéro un, c'est de faire tous ses backups sur le même disque que la source. Un crash, et tout part ensemble. Le deuxième, c'est d'oublier --delete — votre destination gonfle indéfiniment avec des fichiers qui n'existent plus. Et le troisième, le plus dangereux : ne jamais tester la restauration. Le jour où vous en avez besoin, c'est déjà trop tard pour découvrir que le dump était corrompu depuis des semaines.

Aller plus loin

Comprenez la théorie derrière la stratégie 3-2-1 avec notre article sur comprendre la stratégie 3-2-1. Pour une alternative moderne, découvrez Restic comme alternative à rsync. Pour chiffrer vos backups, consultez LUKS.

Conclusion

La stratégie 3-2-1 n'est pas un luxe — c'est un minimum. Rsync vous donne toute la puissance nécessaire pour la mettre en place en moins d'une heure. Automatisez, loggez, testez régulièrement. La prochaine étape logique après ça ? Chiffrer vos backups avec LUKS avant de les envoyer hors site. Mais ça fait un bon article à part.

Besoin d'aide sur ce sujet ?

Notre équipe d'experts est là pour vous accompagner dans vos projets d'infrastructure et d'infogérance.

Contactez-nous

Articles similaires