Aller au contenu

Linux avancé : sauvegarde et automatisation

Une sauvegarde qui n’a jamais été restaurée n’est qu’une hypothèse. Cette page décrit des outils et une méthode ; elle complète Ubuntu Server : commandes utiles et les rubriques de sauvegarde des bases de données (PostgreSQL, MariaDB, MongoDB).

Principe Contenu
3-2-1 3 copies, sur 2 supports différents, dont 1 hors site
Tester la restauration Régulièrement, sur une machine de test
Automatiser Une sauvegarde manuelle finit par être oubliée
Chiffrer Surtout hors site
Surveiller Être alerté si elle échoue
Conserver plusieurs versions Une suppression ou une corruption découverte tard doit rester récupérable
Isoler Une sauvegarde accessible en écriture depuis le serveur est vulnérable à un rançongiciel : préférer un dépôt qui n’accepte que l’ajout

Un RAID ou un instantané n’est pas une sauvegarde (Disques et systèmes de fichiers).

Élément Exemple
Données applicatives /srv/monapp, fichiers téléversés
Bases de données Exports cohérents (pg_dump, mariadb-dump), pas la copie des fichiers de données à chaud
Configuration /etc, /opt/monapp/etc, unités systemd
Liste des paquets dpkg --get-selections > paquets.txt
Secrets et clés Dans un coffre chiffré, séparés des sauvegardes de données
Tâches planifiées crontab -l, systemctl list-timers

Ce qu’on peut reconstruire (paquets, code versionné) n’a pas besoin de sauvegarde ; ce qui est irremplaçable (données, configuration locale) oui.

#!/usr/bin/env bash
set -euo pipefail # arrêt à la première erreur, variables non définies interdites, erreurs de pipe détectées
IFS=$'\n\t'
verrou=/var/lock/sauvegarde.lock
exec 9>"$verrou"
flock -n 9 || { echo "sauvegarde déjà en cours" >&2; exit 1; } # un seul exemplaire à la fois
journal() { logger -t sauvegarde "$*"; echo "$(date '+%F %T') $*"; }
nettoyer() { rm -f "${tmp:-}"; }
trap nettoyer EXIT
trap 'journal "échec ligne $LINENO"; exit 1' ERR
journal "début"
tmp=$(mktemp)
# ... travail ...
journal "fin"
Élément Rôle
set -euo pipefail Arrêter sur erreur plutôt que continuer avec des données partielles
flock -n Empêcher deux exécutions simultanées (une sauvegarde lente chevauche la suivante)
trap … EXIT Nettoyer les fichiers temporaires même en cas d’erreur
logger -t Écrire dans le journal système (Journaux et diagnostic de performance)
mktemp Fichiers temporaires sûrs
Variables entre guillemets ("$dossier") Éviter les accidents avec des noms contenant des espaces (jamais rm -rf $dossier/)

Vérifier les scripts avec ShellCheck (sudo apt install shellcheck, shellcheck script.sh) : voir Bash : bonnes pratiques.

cron Minuteur systemd
Simplicité Une ligne Deux fichiers (service + minuteur)
Journal À rediriger soi-même journalctl -u
Rattrapage si la machine était éteinte Non (sauf anacron) Persistent=true
Dépendances, limites de ressources, isolation Non Oui
État visible Non systemctl list-timers, systemctl status
Fenêtre de terminal
crontab -e
# m h jour mois jour-semaine commande
30 3 * * * /usr/local/bin/sauvegarde.sh >> /var/log/sauvegarde.log 2>&1
0 */6 * * * /usr/local/bin/synchroniser.sh
@reboot /usr/local/bin/au-demarrage.sh

Pièges de cron : environnement minimal (PATH réduit : utiliser des chemins absolus), pas de terminal, le pourcentage % a un sens spécial dans une ligne de crontab (l’échapper \%), les erreurs passent par un courrier local qu’on ne lit pas : toujours rediriger la sortie.

Version recommandée pour un serveur (voir systemd : minuteurs) :

/etc/systemd/system/sauvegarde.service
[Unit]
Description=Sauvegarde quotidienne
[Service]
Type=oneshot
ExecStart=/usr/local/bin/sauvegarde.sh
Nice=10
IOSchedulingClass=idle
/etc/systemd/system/sauvegarde.timer
[Unit]
Description=Sauvegarde quotidienne à 3 h 30
[Timer]
OnCalendar=*-*-* 03:30:00
RandomizedDelaySec=10m
Persistent=true
[Install]
WantedBy=timers.target
Fenêtre de terminal
sudo systemctl daemon-reload
sudo systemctl enable --now sauvegarde.timer
systemctl list-timers sauvegarde.timer
sudo systemctl start sauvegarde.service # essai immédiat
journalctl -u sauvegarde.service -n 50
systemd-analyze calendar "*-*-* 03:30:00" # vérifier une expression
# /etc/systemd/system/sauvegarde.service (ajout)
[Unit]
OnFailure=notification-echec@%n.service
# /etc/systemd/system/notification-echec@.service
[Service]
Type=oneshot
ExecStart=/usr/local/bin/notifier.sh "Échec de %i sur %H"

notifier.sh envoie un message (courriel, webhook, messagerie). Sans notification, un échec de sauvegarde passe inaperçu pendant des mois : tester la notification autant que la sauvegarde. Un contrôle externe (« une sauvegarde est-elle arrivée aujourd’hui ? ») est plus fiable que l’alerte d’échec seule.

Fenêtre de terminal
rsync -aHAX --delete --dry-run /srv/monapp/ /sauvegardes/monapp/ # simulation : lire la sortie
rsync -aHAX --delete /srv/monapp/ /sauvegardes/monapp/
rsync -aHAX --delete -e "ssh -p 22" /srv/monapp/ sauvegarde@stockage.exemple.com:/sauvegardes/monapp/
rsync -a --exclude 'node_modules' --exclude '*.tmp' /srv/monapp/ /sauvegardes/monapp/
rsync -a --info=progress2 --partial /gros/ /destination/
Option Rôle
-a Archive : récursif, droits, propriétaires, dates, liens
-H -A -X Liens physiques, ACL, attributs étendus
--delete Supprime à la destination ce qui n’existe plus à la source (dangereux si la source est vide ou montée en erreur)
--dry-run Simulation
--link-dest Instantanés par liens physiques (voir ci-dessous)
/ final sur la source dossier/ copie le contenu, dossier copie le dossier lui-même

Chaque exécution crée un dossier complet en apparence, mais les fichiers inchangés sont des liens physiques vers la sauvegarde précédente (peu d’espace) :

Fenêtre de terminal
dest=/sauvegardes/monapp
nouvelle="$dest/$(date +%F_%H%M)"
derniere=$(ls -1d "$dest"/20* 2>/dev/null | tail -1 || true)
rsync -aHAX --delete ${derniere:+--link-dest="$derniere"} /srv/monapp/ "$nouvelle/"
ls -1d "$dest"/20* | head -n -14 | xargs -r rm -rf # conserver les 14 plus récentes

restic et borg : sauvegardes dédupliquées et chiffrées

Section intitulée « restic et borg : sauvegardes dédupliquées et chiffrées »

Pour des sauvegardes sérieuses (versions multiples, chiffrement, déduplication, dépôts distants), préférer un outil dédié :

Fenêtre de terminal
sudo apt install restic
export RESTIC_REPOSITORY=sftp:sauvegarde@stockage.exemple.com:/depots/serveur1
export RESTIC_PASSWORD_FILE=/root/.restic-mdp # fichier chmod 600, copie du mot de passe HORS du serveur
restic init
restic backup /srv/monapp /etc --exclude-caches --tag quotidienne
restic snapshots
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 12 --prune
restic check
restic restore latest --target /tmp/restauration --include /srv/monapp/donnees
restic mount /mnt/restic # parcourir les versions
Fenêtre de terminal
sudo apt install borgbackup
borg init --encryption=repokey-blake2 ssh://sauvegarde@stockage.exemple.com/./depots/serveur1
borg create --stats --compression zstd ssh://…::'{hostname}-{now:%F}' /srv/monapp /etc
borg prune --keep-daily 7 --keep-weekly 4 --keep-monthly 12 ssh://…
borg check ssh://…
borg extract ssh://…::serveur1-2026-01-15 srv/monapp/donnees
restic borg
Déduplication, chiffrement Oui Oui
Dépôts distants Nombreux (SFTP, S3, etc.) SSH (et avec des outils annexes)
Mise en place Simple Simple
Remarque Une seule exécutable Gestion de la phrase secrète et de la clé

Ne pas copier les fichiers d’une base en fonctionnement : faire un export cohérent puis le sauvegarder :

Fenêtre de terminal
sudo -u postgres pg_dump -Fc boutique > /var/backups/boutique-$(date +%F).dump
sudo mariadb-dump --single-transaction --all-databases | gzip > /var/backups/mariadb-$(date +%F).sql.gz
redis-cli BGSAVE

Voir les rubriques de chaque base pour les détails ; ajouter les exports à la liste des dossiers sauvegardés (restic, borg).

Fenêtre de terminal
sudo lvcreate -s -n instantane -L 5G /dev/vg_donnees/lv_site
sudo mount -o ro /dev/vg_donnees/instantane /mnt/instantane
restic backup /mnt/instantane
sudo umount /mnt/instantane && sudo lvremove -y /dev/vg_donnees/instantane

L’instantané fige l’état du disque instantanément ; combiné à un export de base de données, il garantit une copie cohérente sans arrêter le service.

Fenêtre de terminal
mkdir /tmp/test-restauration
restic restore latest --target /tmp/test-restauration
diff -r /srv/monapp /tmp/test-restauration/srv/monapp | head
sha256sum -c sommes.sha256
Contrôle Fréquence
Restauration d’un fichier Mensuelle
Restauration complète sur une machine de test Trimestrielle ou à chaque changement majeur
restic check / borg check Hebdomadaire
Alertes qui fonctionnent (test d’échec volontaire) À chaque changement du script

Documenter la procédure de restauration (ordre, mots de passe, temps estimé) : en cas d’incident, elle doit se lire sans réfléchir.

Fenêtre de terminal
flock -n /var/lock/travail.lock ./travail.sh # un seul exemplaire à la fois
timeout 300 ./travail.sh # arrêt après 5 minutes
echo "./nettoyer.sh" | at now + 2 hours # exécution unique différée (paquet at)
atq; atrm 3
parallel -j4 ./traiter.sh ::: fichier*.csv # parallélisme (paquet parallel)
xargs -P4 -n1 ./traiter.sh < liste.txt
watch -n 5 'systemctl is-active monapp'
Symptôme Piste
La tâche cron ne s’exécute pas grep CRON /var/log/syslog, chemins absolus, droits d’exécution, % non échappé
Elle marche à la main mais pas par cron Environnement minimal : PATH complet dans le script ou la crontab
Le minuteur ne se déclenche pas systemctl list-timers --all, systemctl status sauvegarde.timer, expression OnCalendar
Deux sauvegardes se chevauchent flock, ou durée supérieure à l’intervalle
Sauvegarde vide ou incomplète Source démontée (set -e, contrôle avant --delete), erreurs ignorées
restic/borg : repository is locked Autre exécution en cours, ou arrêt brutal : restic unlock après vérification
Dépôt qui grossit trop forget --prune, politique de conservation
Échec silencieux Notification OnFailure, contrôle externe de présence d’une sauvegarde récente
Permission denied à la sauvegarde Utilisateur du service, ACL, fichiers non lisibles : exécuter en root ou ajuster les droits

Ubuntu 24.04 et 26.04 : différences à connaître

Section intitulée « Ubuntu 24.04 et 26.04 : différences à connaître »

Les paquets restic et borgbackup sont disponibles dans les dépôts d’Ubuntu (versions variables : vérifier apt policy restic). Sur 26.04, /tmp est en mémoire : ne pas y placer de gros fichiers temporaires de sauvegarde (utiliser /var/tmp). Les minuteurs systemd fonctionnent de la même façon (systemd 255 et 259).