Cours Linux / Automatiser une sauvegarde et surveiller l’état du serveur
Pour exploiter un serveur, il faut à la fois une sauvegarde restaurable et un contrôle qui signale les pannes ou les tâches jamais exécutées. Vérifiez séparément la création de l’archive, son empreinte, la restauration dans un dossier vide, la réponse HTTP et l’espace libre ; faites aussi vérifier depuis l’extérieur l’âge de la dernière sauvegarde, car une machine arrêtée ne peut pas signaler sa propre absence.
Cet atelier prolonge le cours de sauvegarde et restauration avec tar.gz et celui sur cron et les timers systemd. Il cible des fichiers statiques d’une VM Ubuntu 26.04 LTS ou Rocky Linux 9 : un site Nginx comme dans le cours de publication HTTP et HTTPS est un exemple. Les commandes doivent être adaptées au compte, aux chemins et à la politique de sécurité de votre serveur ; un conteneur ou WSL peut présenter d’autres fonctions de journalisation et planification.
Définir les données protégées et le niveau de récupération
Le script ci-dessous archive un répertoire de fichiers ordinaires peu modifiés pendant l’opération, par exemple une copie de contenu statique. Il ne garantit pas un instantané cohérent d’une base de données ou de fichiers en cours d’écriture. Pour une base de données, utilisez sa méthode de sauvegarde cohérente ; pour un service complet, documentez aussi sa configuration, ses secrets, ses certificats, son DNS et la procédure de déploiement. Un fichier tar.gz seul n’est pas un plan de restauration complet.
Déterminez les points de restauration nécessaires, la durée maximale acceptable de perte de données et le temps disponible pour remettre le service en ligne. Un dossier de sauvegarde situé sur le même disque apprend le mécanisme, mais ne résiste pas à la perte de ce disque ou du compte qui y a accès. Transférez les copies utiles vers un stockage séparé avec droits, chiffrement et conservation adaptés, puis effectuez aussi un essai de restauration depuis cette copie distante. Utilisez un compte dédié et des permissions minimales en exploitation ; n’exécutez pas par défaut tout le travail comme root.
Créer un script de sauvegarde sans écraser une copie
Le script attend un répertoire source existant et un répertoire de destination existant, tous deux accessibles au compte qui l’exécute. Vérifiez la présence de bash, realpath, mktemp, tar et sha256sum. L’exemple crée $HOME/bin/course-backup-fr.sh uniquement si ce nom est libre. Si le fichier existe, choisissez un autre nom et adaptez les commandes suivantes ; ne l’écrasez pas.
mkdir -p -- "$HOME/bin"
script="$HOME/bin/course-backup-fr.sh"
if [[ -e "$script" || -L "$script" ]]; then
printf 'Script déjà présent : choisir un autre nom\n' >&2
else
cat > "$script" <<'EOF'
#!/usr/bin/env bash
set -u
set -o pipefail
umask 077
if (( $# != 2 )); then
printf 'Usage : %s DOSSIER_SOURCE DOSSIER_SAUVEGARDE\n' "$0" >&2
exit 2
fi
source_dir=$(realpath -e -- "$1") || exit 1
backup_dir=$(realpath -e -- "$2") || exit 1
[[ -d "$source_dir" && -d "$backup_dir" ]] || exit 1
case "$backup_dir/" in
"$source_dir/"*) printf 'La destination est dans la source\n' >&2; exit 1 ;;
esac
case "$source_dir/" in
"$backup_dir/"*) printf 'La source est dans la destination\n' >&2; exit 1 ;;
esac
work=$(mktemp -d "$backup_dir/backup.XXXXXXXX") || exit 1
if ! tar -czf "$work/data.tar.gz" -C "$source_dir" .; then
printf 'Échec de l’archive : %s\n' "$work" >&2; exit 1
fi
if ! tar -tzf "$work/data.tar.gz" > /dev/null; then
printf 'Archive illisible : %s\n' "$work" >&2; exit 1
fi
if ! (cd "$work" && sha256sum data.tar.gz > data.tar.gz.sha256); then
printf 'Échec de l’empreinte\n' >&2; exit 1
fi
date --iso-8601=seconds > "$work/created-at.txt" || exit 1
printf 'complete\n' > "$work/COMPLETE" || exit 1
printf 'Sauvegarde prête : %s\n' "$work"
EOF
bash -n "$script"
fi
mktemp -d crée un dossier distinct à chaque passage et umask 077 limite les droits des nouveaux fichiers. La marque COMPLETE est écrite en dernier : si l’exécution échoue, un dossier partiel peut rester, mais ne doit pas être présenté comme une copie valide. L’archive peut contenir des liens symboliques, permissions et chemins qui demandent une inspection avant extraction ; ne restaurez que des archives que vous contrôlez dans un répertoire vide. L’empreinte détecte une modification accidentelle de l’archive, mais une personne capable de remplacer archive et empreinte peut tromper ce contrôle. Un stockage distant séparé apporte la protection contre la panne du disque local, sous réserve de sa configuration réelle.
Exécuter puis restaurer dans un dossier vide
Créez des données sans secret dans un nouveau dossier de pratique, séparé du site de production. Si un dossier de même nom existe, choisissez un autre nom ou examinez son contenu avant de poursuivre. Le script ne nettoie pas ce laboratoire automatiquement pour éviter une suppression imprévue.
lab=$(mktemp -d "$HOME/linux-ops-lab.XXXXXX") || exit 1
mkdir -- "$lab/site" "$lab/backups" "$lab/restored"
printf 'version du site 1\n' > "$lab/site/index.html"
bash "$HOME/bin/course-backup-fr.sh" "$lab/site" "$lab/backups"
find "$lab/backups" -maxdepth 2 -type f -print
La ligne « Sauvegarde prête » donne le chemin du dossier réellement créé. Recopiez-le dans backup ci-dessous, sans conserver littéralement CHEMIN_SAUVEGARDE_REEL. Vérifiez la marque et l’empreinte, puis extrayez vers le dossier vide du même laboratoire :
backup=CHEMIN_SAUVEGARDE_REEL
test -f "$backup/COMPLETE"
(cd "$backup" && sha256sum -c data.tar.gz.sha256)
tar -tzf "$backup/data.tar.gz"
tar -xzf "$backup/data.tar.gz" -C "$lab/restored"
diff -r -- "$lab/site" "$lab/restored"
Attendez data.tar.gz: OK, une liste incluant le fichier de test, puis aucune différence signalée par diff. Exécutez chaque commande et arrêtez-vous à la première erreur : le simple affichage de l’archive ne garantit ni l’extraction ni le fonctionnement d’une application. Contrôlez aussi les permissions, propriétaires et étiquettes nécessaires sur la vraie cible ; restaurez en dehors de la production avant tout remplacement. Le manuel GNU tar décrit le contenu et l’extraction. Après transfert hors serveur, répétez la vérification d’empreinte et une restauration depuis la copie distante.
Surveiller une réponse HTTP et l’espace libre
Ce second script demande curl, df et awk. Il reçoit l’URL de l’application, un minimum d’espace libre en kibioctets (KiB) et un chemin sur le volume à contrôler. Il considère les codes HTTP 200 à 299 comme un succès ; une application qui doit répondre par redirection ou authentification demandera un critère adapté. L’URL doit désigner le vrai site visé, pas seulement la page par défaut de Nginx. Le script ne vérifie ni le contenu exact de la réponse ni la base de données.
health="$HOME/bin/course-health-fr.sh"
if [[ -e "$health" || -L "$health" ]]; then
printf 'Script déjà présent : choisir un autre nom\n' >&2
else
cat > "$health" <<'EOF'
#!/usr/bin/env bash
set -u
set -o pipefail
if (( $# != 3 )); then
printf 'Usage : %s URL MIN_KIB_LIBRES CHEMIN_STOCKAGE\n' "$0" >&2; exit 2
fi
url=$1
minimum=$2
path=$3
[[ "$url" == http://* || "$url" == https://* ]] || exit 2
[[ "$minimum" =~ ^[0-9]+$ ]] || exit 2
if ! status=$(curl -sS -o /dev/null -w '%{http_code}' --connect-timeout 5 --max-time 15 "$url"); then
printf 'Échec de la connexion HTTP\n' >&2; exit 1
fi
[[ "$status" =~ ^2[0-9][0-9]$ ]] || {
printf 'Code HTTP=%s\n' "$status" >&2; exit 1;
}
available=$(df -Pk -- "$path" | awk 'NR==2 {print $4}') || exit 1
[[ "$available" =~ ^[0-9]+$ ]] || exit 1
(( 10#$available >= 10#$minimum )) || {
printf 'Espace faible : %s KiB\n' "$available" >&2; exit 1;
}
printf 'OK http=%s libres_kib=%s\n' "$status" "$available"
EOF
bash -n "$health"
fi
Sur une VM où le site local répond sous le bon nom, lancez par exemple bash "$HOME/bin/course-health-fr.sh" http://127.0.0.1/ 102400 "$HOME" seulement si cette URL atteint réellement votre service. 102400 KiB, soit environ 100 MiB, est un seuil de démonstration, pas une valeur de production. Choisissez le chemin du volume qui héberge les données importantes et fixez une marge selon sa croissance et l’espace nécessaire à la restauration ; surveillez les inodes séparément. Les options de curl limitent ici la durée de connexion et celle de toute la requête.
Planifier, détecter l’absence et tester l’alerte
Après réussite manuelle, placez la commande de sauvegarde dans un service et un timer utilisateur suivant le cours de planification. Remplacez la commande de l’unité par l’appel à Bash, au script et aux deux chemins réels ; vérifiez le chemin de Bash avec command -v bash et la syntaxe des arguments systemd, surtout si des chemins contiennent des espaces. Exécutez d’abord cette commande seule sous le même compte que l’unité. Choisissez la fréquence selon la perte de données tolérable et vérifiez l’environnement et la durée de vie du gestionnaire utilisateur après déconnexion ou redémarrage. Gardez la surveillance HTTP dans une unité distincte, avec son propre résultat.
Le statut « timer actif » ne signifie pas « dernière sauvegarde restaurable ». Contrôlez l’heure de la prochaine exécution, le code de sortie du service, la présence du marqueur COMPLETE, l’âge de cette copie et des restaurations périodiques. Un contrôle sur le même serveur ne détecte pas un arrêt total de ce serveur ; un moniteur situé ailleurs doit vérifier la vraie URL publique et que l’âge de la dernière sauvegarde ne dépasse pas votre limite. Testez la réception d’une alerte en provoquant un échec de pratique et en confirmant qu’une personne sait comment réagir. Protégez le canal d’alerte contre la divulgation de secrets des journaux.
Provoquer un échec contrôlé et ranger l’atelier
Dans la VM de pratique, donnez une source inexistante au script de sauvegarde : il doit échouer sans produire une nouvelle copie marquée COMPLETE. Demandez au contrôle HTTP une URL locale inexistante ou un chemin qui renvoie 404, puis un seuil d’espace libre supérieur à la capacité du volume ; vérifiez chaque code de sortie séparément et restaurez les paramètres réels après chaque essai. Une requête vers une machine distante qui n’est pas à vous n’est pas nécessaire. Ces essais n’établissent pas encore que l’alerte externe fonctionne : testez-la à son tour.
Arrêtez et désactivez les seuls timers créés pour cet exercice avant de retirer leurs unités. Inspectez lab et les chemins des scripts, puis ne supprimez que vos propres fichiers d’essai. Ne purgez pas par commodité toutes les copies historiques : appliquez une durée de conservation écrite et vérifiez qu’au moins les points de restauration nécessaires restent disponibles.




