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).
Principes
Section intitulée « Principes »| 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).
Que sauvegarder
Section intitulée « Que sauvegarder »| É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.
Scripts robustes
Section intitulée « Scripts robustes »#!/usr/bin/env bashset -euo pipefail # arrêt à la première erreur, variables non définies interdites, erreurs de pipe détectéesIFS=$'\n\t'
verrou=/var/lock/sauvegarde.lockexec 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 EXITtrap '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.
Planifier : cron ou minuteur systemd
Section intitulée « Planifier : cron ou minuteur systemd »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 |
crontab -e# m h jour mois jour-semaine commande30 3 * * * /usr/local/bin/sauvegarde.sh >> /var/log/sauvegarde.log 2>&10 */6 * * * /usr/local/bin/synchroniser.sh@reboot /usr/local/bin/au-demarrage.shPiè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) :
[Unit]Description=Sauvegarde quotidienne
[Service]Type=oneshotExecStart=/usr/local/bin/sauvegarde.shNice=10IOSchedulingClass=idle[Unit]Description=Sauvegarde quotidienne à 3 h 30
[Timer]OnCalendar=*-*-* 03:30:00RandomizedDelaySec=10mPersistent=true
[Install]WantedBy=timers.targetsudo systemctl daemon-reloadsudo systemctl enable --now sauvegarde.timersystemctl list-timers sauvegarde.timersudo systemctl start sauvegarde.service # essai immédiatjournalctl -u sauvegarde.service -n 50systemd-analyze calendar "*-*-* 03:30:00" # vérifier une expressionNotifier un échec
Section intitulée « Notifier un échec »# /etc/systemd/system/sauvegarde.service (ajout)[Unit]OnFailure=notification-echec@%n.service# /etc/systemd/system/notification-echec@.service[Service]Type=oneshotExecStart=/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.
rsync : copie incrémentale
Section intitulée « rsync : copie incrémentale »rsync -aHAX --delete --dry-run /srv/monapp/ /sauvegardes/monapp/ # simulation : lire la sortiersync -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 |
Instantanés avec --link-dest
Section intitulée « Instantanés avec --link-dest »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) :
dest=/sauvegardes/monappnouvelle="$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écentesrestic 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é :
sudo apt install resticexport RESTIC_REPOSITORY=sftp:sauvegarde@stockage.exemple.com:/depots/serveur1export RESTIC_PASSWORD_FILE=/root/.restic-mdp # fichier chmod 600, copie du mot de passe HORS du serveurrestic initrestic backup /srv/monapp /etc --exclude-caches --tag quotidiennerestic snapshotsrestic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 12 --prunerestic checkrestic restore latest --target /tmp/restauration --include /srv/monapp/donneesrestic mount /mnt/restic # parcourir les versionssudo apt install borgbackupborg init --encryption=repokey-blake2 ssh://sauvegarde@stockage.exemple.com/./depots/serveur1borg create --stats --compression zstd ssh://…::'{hostname}-{now:%F}' /srv/monapp /etcborg 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é |
Exports de bases de données
Section intitulée « Exports de bases de données »Ne pas copier les fichiers d’une base en fonctionnement : faire un export cohérent puis le sauvegarder :
sudo -u postgres pg_dump -Fc boutique > /var/backups/boutique-$(date +%F).dumpsudo mariadb-dump --single-transaction --all-databases | gzip > /var/backups/mariadb-$(date +%F).sql.gzredis-cli BGSAVEVoir les rubriques de chaque base pour les détails ; ajouter les exports à la liste des dossiers sauvegardés (restic, borg).
Instantanés LVM pour une sauvegarde cohérente
Section intitulée « Instantanés LVM pour une sauvegarde cohérente »sudo lvcreate -s -n instantane -L 5G /dev/vg_donnees/lv_sitesudo mount -o ro /dev/vg_donnees/instantane /mnt/instantanerestic backup /mnt/instantanesudo umount /mnt/instantane && sudo lvremove -y /dev/vg_donnees/instantaneL’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.
Tester la restauration
Section intitulée « Tester la restauration »mkdir /tmp/test-restaurationrestic restore latest --target /tmp/test-restaurationdiff -r /srv/monapp /tmp/test-restauration/srv/monapp | headsha256sum -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.
Autres outils d’automatisation
Section intitulée « Autres outils d’automatisation »flock -n /var/lock/travail.lock ./travail.sh # un seul exemplaire à la foistimeout 300 ./travail.sh # arrêt après 5 minutesecho "./nettoyer.sh" | at now + 2 hours # exécution unique différée (paquet at)atq; atrm 3parallel -j4 ./traiter.sh ::: fichier*.csv # parallélisme (paquet parallel)xargs -P4 -n1 ./traiter.sh < liste.txtwatch -n 5 'systemctl is-active monapp'Dépannage
Section intitulée « Dépannage »| 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).
Pour aller plus loin
Section intitulée « Pour aller plus loin »- Manuels :
man rsync,man crontab,man systemd.timer, restic, BorgBackup - Retour : Processus et ressources