Ma stratégie de sauvegarde


J’ai révisé le 8 septembre 2024 ma stratégie de sauvegarde et je vous propose ici sa mise à jour. Elle pnécessite une interruption de tous les services le temps de la sauvegarde. Dans mon cas, cette interruption – à l’exception de la sauvegarde initiale qui est beaucoup plus longue – est de l’ordre de 4 à 6 minutes par nuit, en complément d’une interruption de l’ordre d’une demi-heure le dimanche. Ces interruptions ayant lieu la nuit, elles ne posent pas de problème dans mon cas. Si votre service est utilisé sur plusieurs fuseaux horaires, cela risque toutefois de vous handicaper.


Je conseille la lecture de cet article aux auto-hébergeurs qui ont suivi la démarche proposée jusqu’à l’installation d’Immich et de Vaultwarden via Docker, et de l’outil de notification Ntfy. En effet, les procédures de sauvegarde sont très liées au patrimoine informationnel à sauvegarder et la stratégie décrite ici n’a de sens que pour une installation similaire à la mienne.

Comme je l’ai indiqué dans un précédent article, les sauvegardes constituent un élément-clé de toute installation auto-hébergée. La stratégie est basée sur l’analyse de son système, des éléments qui peuvent être reconstitués (le système d’exploitation, l’installation des applications, …) et de ceux qui doivent être protégés (les données, les bases de données, les paramétrages applicatifs, …). Elle est aussi basée sur la tolérance à la perte de données : si je pers les modifications d’une journée, est-ce acceptable ?…

C’est sur la base de cette analyse que chacun pourra déterminer les procédures et les outils à mettre en oeuvre. Ensuite, il faut avoir en tête les contraintes spécifiques à chaque composant de son système :

  • le système d’exploitation et les applications sont en mouvement permanent : à chaque minute de nouvelles informations sont prises en compte qui viennent modifier son état ; mais ils sont faciles à réinstaller si un problème est rencontré (réinstallation de l’OS et recopie des fichiers docker-compose.yml).
  • les données applicatives sont généralement stables tant qu’un utilisateur ne vient pas les modifier,
  • enfin, les bases de données sont quelquefois de grosses entités susceptibles d’évoluer entre le début d’une prise de photo et sa fin, les mettant dans un état instable et générant des copies inexploitables.

C’est sur la base de ces éléments que j’ai construit ma stratégie de sauvegarde :

  • une copie quotidienne de mes données (pour l’essentiel des volumes Docker), en mode incrémentiel et compressé, avec BorgBackup,
  • une copie hebdomadaire des données : pour le cas où l’outil BorgBackup ne permettrait pas de restaurer la sauvegarde incrémentielle et compressée, j’aurais toujours une copie complète du dernier état hebdomadaire de mes données,
  • une copie mensuelle froide et hors réseau, pour le cas où mon système aurait été totalement compromis (incendie, attaque par rançongiciel, …).

Ces sauvegardes sont orchestrées par un déclenchement automatisé via les mécanismes cron.

Les sauvegardes que je présente dans cette base sont réalisées sur site, sur un disque dur mécanique différent de celui utilisé pour la production, afin que lorsque ce dernier tombera en panne, tous les éléments nécessaires au rétablissement de la production soient disponibles sur le deuxième disque. En complément, je réalise également une sauvegarde froide hors site et hors réseau.

La sauvegarde des données avec BorgBackup

BorgBackup est un outil puissant pour réaliser des sauvegardes. Il permet notamment de générer des sauvegardes hors site, compressées, incrémentielles, cryptées, …

Pour ma part, je réalise mes sauvegardes sur site et non-cryptées, et je ne fais qu’une sauvegarde froide mensuelle. Mais si vous disposez d’un accès hors site (serveur dans les nuages, ou chez un ami ou un parent), il sera intéressant d’utiliser les fonctionnalités de cryptage et de connexion distante. Attention : ne procédez pas à une connexion distante sans cryptage ; vos données pourraient alors être interceptées et lues de manière absolument transparentes.

Pour effectuer la sauvegarde de l’ensemble des données dans un état stable, j’interromps momentanément l’ensemble des conteneurs Docker qui fournissent les services. Comme les utilisateurs de mes services sont peu nombreux et dorment – comme moi – pendant la sauvegarde, cela ne pose pas de problème.

Pour installer BorgBackup, rien de plus simple :

sudo apt install borgbackup

Il nous faut ensuite créer puis initialiser le répertoire cible de la sauvegarde ; pour ma part, je l’ai installé sur /srv/hdd/borg.

sudo mkdir /srv/hdd/borg
borg init --encryption=none /srv/hdd/borg

Vous trouverez dans la documentation de BorgBackup les autres options de cryptage, si vous souhaitez en mettre en oeuvre.

J’ai ensuite créé sur l’application Ntfy sur mon téléphone Android un sujet Sauvegarde pour recevoir les notifications de succès ou d’échec de mes sauvegardes.

A l’issue de quoi j’ai mis en place un script issu de celui proposé par BorgBackup en l’adaptant à ma situation (sauvegarde incrémentielle, compressée, pas de cryptage et de connexion distante) ; je l’ai nommé borgbackup.sh, au sein d’un répertoire sauvegarde. Je l’ai modifié afin qu’il interrompe les conteneurs actifs le temps de la sauvegarde et rétablisse leur fonctionnement lorsqu’elle est arrivée à son terme.

#!/bin/sh

# Setting this, so the repo does not need to be given on the commandline:
export BORG_REPO=/srv/hdd/borg

# See the section "Passphrase notes" for more infos.
# export BORG_PASSPHRASE='XYZl0ngandsecurepa_55_phrasea&&123'

# some helpers and error handling:
info() { printf "\n%s %s\n\n" "$( date )" "$*" >&2; }
trap 'echo $( date ) Backup interrupted >&2; exit 2' INT TERM

info "Starting backup"

# Stop Docker containers

CONTAINERS=$(docker ps -q)

docker stop --time=180 $CONTAINERS

# Backup the most important directories into an archive named after
# the machine this script is currently running on:

borg create                         \
    --verbose                       \
    --filter AME                    \
    --list                          \
    --stats                         \
    --show-rc                       \
    --compression lz4               \
    --exclude /home/k-sper.fr/sauvegarde/borgbackup.log \
                                    \
    ::'{hostname}-{now:%Y-%m-%d_%H:%M}' \
    /srv/nas			    \
    /home/k-sper.fr			    \
    2> /home/k-sper.fr/sauvegarde/borgbackup.log

backup_exit=$?

# Start Docker containers

docker start $CONTAINERS

info "Pruning repository"

# Use the `prune` subcommand to maintain 7 daily, 4 weekly and 6 monthly
# archives of THIS machine. The '{hostname}-*' matching is very important to
# limit prune's operation to this machine's archives and not apply to
# other machines' archives also:

borg prune                          \
    --list                          \
    --glob-archives '{hostname}-*'  \
    --show-rc                       \
    --keep-daily    7               \
    --keep-weekly   4               \
    --keep-monthly  6		    \
    2>> /home/k-sper.fr/sauvegarde/borgbackup.log

prune_exit=$?

# actually free repo disk space by compacting segments

info "Compacting repository"

borg compact 2>> /home/k-sper.fr/sauvegarde/borgbackup.log

compact_exit=$?

# use highest exit code as global exit code
global_exit=$(( backup_exit > prune_exit ? backup_exit : prune_exit ))
global_exit=$(( compact_exit > global_exit ? compact_exit : global_exit ))

sleep 120

# Notification de résultat de la sauvegarde

if [ ${global_exit} -eq 0 ]; then
    info "Backup, Prune, and Compact finished successfully"
    curl -H prio:1 -d "Sauvegarde Borg réussie" -u k-sper.fr:<clé Ntfy> https://ntfy.k-sper.fr/backup
elif [ ${global_exit} -eq 1 ]; then
    info "Backup, Prune, and/or Compact finished with warnings"
    curl -H prio:3 -d "Sauvegarde Borg à vérifier" -u k-sper.fr:<clé Ntfy> https://ntfy.k-sper.fr/backup
else
    info "Backup, Prune, and/or Compact finished with errors"
    curl -H prio:3 -d "Sauvegarde Borg en erreur" -u k-sper.fr:<clé Ntfy> https://ntfy.k-sper.fr/backup
fi

exit ${global_exit}

Analysons rapidement ce script :

  • la première section définit le répertoire cible, que nous avons initialisé,
  • la seconde renseigne la clé de cryptage ; comme je n’ai pas choisi d’activer cette fonction, la ligne correspondante est commentée,
  • la troisième initialise le journal,
  • ensuite, je définis la variable CONTAINERS comme la liste des identifiants des conteneurs Docker en fonctionnement et j’arrête tous les conteneurs ; évidemment il ne faut pas que Borg soit installée via Docker sans quoi la sauvegarde s’arrêterait aussi,
  • puis vient avec « borg create » la commande de création d’une nouvelle sauvegarde ; c’est dans cette section que devront figurer les options de la sauvegarde que vous souhaitez réaliser ; j’envoie les résultats dans un fichier journal /home/k-sper.fr/sauvegarde/borgbackup.log* : cela me permettra en cas d’échec de la sauvegarde, de vérifier ce qui a dysfonctionné,
  • je relance l’ensemble des conteneurs en m’appuyant à nouveau sur la variable CONTAINERS,
  • la suivante supprime les sauvegardes trop anciennes de manière à limiter l’espace de stockage utilisé ; elle indique ici que seront conservés :
    • les sept dernières sauvegardes quotidiennes,
    • les quatre dernières sauvegardes hebdomadaires,
    • et les six dernières sauvegardes mensuelles,
  • les sections suivantes compactent les données et gèrent les éventuels échecs de suppression des sauvegardes anciennes,
  • enfin, la dernière section met en place un compte-rendu de la sauvegarde via une notification Ntfy.

* Vous aurez remarqué la notation « 2> » qui permet d’alimenter le fichier journal ; cela est effectué via une redirection ou « pipe » pour les anglophones ; cette notation indique que les flux normalement orientés vers la sortie stderr sont réorientés vers un fichier.

J’ai maintenant le script qui commande les sauvegardes. Je le rends exécutable :

sudo +x borgbackup.sh

Et je m’assure qu’il peut être déclenché par l’utilisateur root ; je modifie son propriétaire si nécessaire :

sudo chown root:root borgbackup.sh

Je le déclenche. Attention : selon le volume des données à sauvegarder, son déroulement peut durer de nombreuses heures. Gardons en tête que la déconnexion de la session interrompt brutalement les travaux en cours. Aussi, je vais utiliser la commande screen pour lancer une session dont je pourrai me détacher sans interrompre les travaux :

sudo apt update
sudo apt upgrade
sudo apt install screen
screen -S sauvegarde

Je suis maintenant à l’intérieur de la nouvelle session, qui s’appelle sauvegarde. Je lance mon script :

sudo ./borgbackup.sh

Le script est maintenant lancé. A tout moment je peux « me détacher » de la session tout en la laissant exécuter le script. Pour cela, il me suffit de taper CTRL+A puis D. Me voilà alors revenu sur la session d’origine, que je peux éventuellement quitter si je le souhaite. Pour revenir à ma session de sauvegarde, il me suffira alors de taper :

screen -r sauvegarde

Je laisse donc la sauvegarde initiale se dérouler, et je vais en parallèle, dans la session initiale, organiser la programmation des sauvegardes régulières. Pour cela, je vais utiliser la commande crontab. Cette commande permet d’éditer les fichiers cron et ainsi de paramétrer le déclenchement d’actions régulières.

sudo crontab -e

Je lance la commande avec sudo afin que les travaux de sauvegarde soient lancés par l’utilisateur root. Ainsi je n’aurai pas de problème d’autorisations dans les accès aux fichiers à sauvegarder.

Le fichier qui s’ouvre se présente comme ceci :

Je vais insérer en fin de fichier la ligne suivante :

0 2 * * * /home/k-sper.fr/sauvegarde/borgbackup.sh

Dans cron, les cinq premières positions servent à définir la date et l’heure de déclenchement des actions :

  1. les minutes ; le 0 indique que l’action sera déclenchée à 0 minutes au sein d’une heure,
  2. les heures ; l’action sera déclenchée à 2 h,
  3. le numéro du jour dans le mois ; le caractère « * » indique que l’action doit être déclenchée quel que soit le jour du mois,
  4. le numéro du mois,
  5. le jour de la semaine.

Ainsi, le script /home/k-sper.fr/sauvegarde/borgbackup.sh sera exécuté tous les jours à 3h du matin.

La restauration de ma sauvegarde Borg

Borg me permet d’historiser mes sauvegardes. Je dispose de la sauvegarde de cette nuit, de la précédente, etc. Je peux donc choisir celle qui conviendra en vue de ma restauration. Dans certains cas, je pourrai choisir des données anciennes car je me rends compte que les plus récentes sont corrompues. Je pourrai aussi décider – après une bonne réflexion sur les effets de bord – de restaurer les données les plus récentes de certaines applications et de plus anciennes pour une d’entre elles, etc.

Si j’ai dû réinstaller tout mon système, il faut bien évidemment que je réinstaller BorgBackup ; je ne vous refais pas la démarche.

Pour la restauration, je vais créer un répertoire dédié au montage de ma sauvegarde.

sudo mkdir /mnt/borg

Je vais faire la liste des sauvegardes disponibles via Borg :

sudo borg list /srv/hdd/borg

Je peux alors décider de monter la sauvegarde la plus récente sur mon point de montage :

sudo borg mount /srv/hdd/borg::odroid-2024-05-15_02:03 /mnt/borg

Maintenant, si je liste les données du répertoire /mnt/borg, je les retrouve telles qu’elles ont été sauvegardées le 15 mai à 2 h du matin :

sudo ls /mnt/borg

Attention : je ne peux pas me déplacer à l’intérieur du répertoire /mnt/borg car il appartient à l’utilisateur root et que je n’ai pas les droits pour y accéder. Mais je peux lire toutes les données qui y figurent.

Je peux ensuite choisir les données que je veux restaurer, par exemple le répertoire qui contient toutes mes photographies stockées via Immich. Il est disponible à /mnt/borg/srv/nas/immich.

Pour les restaurer, je vais utiliser la commande rsync, qui permet la copie des fichiers en conservant leurs propriétés. Je vous conseille de vous approprier le fonctionnement de rsync, dont vous aurez besoin à un moment ou à un autre dans vos activités d’auto-hébergement.

Je choisis l’emplacement de la restauration, par exemple à nouveau /srv/nas, et je lance donc :

sudo rsync -atv /mnt/borg/srv/nas/immich /srv/nas/

Il me faut un peu de patience car il s’agit d’un répertoire de grande taille, mais je peux observer la restauration grâce à l’option -v qui affiche l’avancement fichier par fichier.

La sauvegarde hebdomadaire des données

En complément des sauvegardes ci-dessus, j’ai également mis en place une copie simple des données et des sous-répertoires de /home/k-sper.fr, déclenchée toutes les semaines. En effet, la sauvegarde réalisée par BorgBackup est une sauvegarde compressée et incrémentielle. Si pour une raison ou pour une autre les algorithmes de compression ou de gestion des incréments dysfonctionnent, je me retrouve avec une « sauvegarde » inutilisable. J’ai donc prévu une copie toute simple des données basée sur rsync.

Je reviens dans le répertoire sauvegarde, où j’avais déposé le script borgbackup.sh, et je vais créer les fichiers suivants :

sudo touch backup_k-sper.fr.err
sudo touch backup_k-sper.fr.log
sudo touch backup_nas.err
sudo touch backup_nas.log

Ces fichiers vont me servir de journaux pour mes traitements de sauvegardes.

Et je crée le fichier backup.sh :

sudo nano backup.sh
#!/bin/bash

# Initialisation du journal

echo "Lancement de la sauvegarde :" `date` > /home/k-sper.fr/sauvegarde/backup_k-sper.fr.log

############# Sauvegarde paquets

  dpkg --get-selections > /home/k-sper.fr/sauvegarde/backup_paquets

############# Sauvegarde répertoire home

if [ $(rsync -aucv --delete-during /home/k-sper.fr /srv/hdd >> /home/k-sper.fr/sauvegarde/backup_k-sper.fr.log 2> /home/k-sper.fr/sauvegarde/backup_k-sper.fr.err) ]; then

  R1=-1

else

  R1=1

fi

# Compte-rendu ntfy

if R1=1 ; then

  curl -H prio:1 -d "Sauvegarde home réussie" -u k-sper.fr:<clé Ntfy> https://ntfy.k-sper.fr/backup

else

  curl -H prio:3 -d "Sauvegarde home en échec" -u k-sper.fr:<clé Ntfy> https://ntfy.k-sper.fr/backup

fi

sleep 60

echo "Fin de la sauvegarde : " `date` >> /home/k-sper.fr/sauvegarde/backup_k-sper.fr.log

############# Sauvegarde NAS

echo "Lancement de la sauvegarde :" `date` > /home/k-sper.fr/sauvegarde/backup_nas.log

# Arrêt des conteneurs

CONTAINERS=$(docker ps -q)

echo $CONTAINERS

docker stop --time=180 $CONTAINERS  > /home/k-sper.fr/sauvegarde/backup_nas.log 2> /home/k-sper.fr/sauvegarde/backup_nas.err

if [ $(rsync -aucv --delete-during /srv/nas /srv/hdd/nas > /home/k-sper.fr/sauvegarde/backup_nas.log 2> /home/k-sper.fr/sauvegarde/backup_nas.err) ]; then

  R2=-1

else

  R2=1

fi

# Redémarrage des conteneurs

docker start $CONTAINERS  > /home/k-sper.fr/sauvegarde/backup_nas.log 2> /home/k-sper.fr/sauvegarde/backup_nas.err

sleep 240

echo "Fin de la sauvegarde :" `date` >> /home/k-sper.fr/sauvegarde/backup_nas.log

# Compte-rendu ntfy

if R2=1 ; then

  curl -H prio:1 -d "Sauvegarde NAS réussie" -u k-sper.fr:<clé Ntfy> https://ntfy.k-sper.fr/backup

else

  curl -H prio:3 -d "Sauvegarde NAS en échec" -u k-sper.fr:<clé Ntfy> https://ntfy.k-sper.fr/backup

fi

La première ligne non-commentée initialise le journal, puis la suivante recense les paquets installés sur mon système, de manière à ce que j’en garde une trace dans l’éventualité où mon système serait corrompu et nécessiterait une reconstruction complète.

La ligne suivante réalise la sauvegarde du répertoire /home/k-sper.fr (pour l’essentiel des répertoires contenant les paramétrages des conteneurs Docker). Les options (-atucv) sont essentielles à la restauration le cas échéant. Attardons-nous un peu dessus :

  • -a : mode archivage; identique à -rlptgoD ; en clair, les propriétés des fichiers sont conservées à l’identique,
  • -u : saute les fichiers plus récents chez le destinataire ; cette option n’est pas indispensable, dans la mesure où l’image cible de la sauvegarde ne devrait pas comprendre de fichiers plus récents que celle d’origine,
  • -c : utilise la somme de contrôle pour déterminer si un fichier a évolué, pas la date ni la taille,
  • -v : mode verbeux afin de disposer d’un journal détaillé et de pouvoir le cas échéant analyser les anomalies rencontrées.

Puis, sont générées les notifications de succès ou d’échec de ce traitement.

Enfin, la sauvegarde des données du NAS, suivie des notifications de succès ou d’échec afférentes.

Je rends ce script exécutable :

sudo chmod +x backup.sh

Et je programme son lancement hebdomadaire :

sudo crontab -e
0 3 * * 0 /home/k-sper.fr/sauvegarde/backup.sh

Cette ligne lance le backup chaque dimanche à 3 h du matin.

La restauration de cette sauvegarde est simple puisqu’elle est présente en clair sur le disque dur. Attention : pour restaurer, n’utilisez pas la commande cp, qui copierait sans respecter les propriétés des fichiers, mais la commande rsync, avec l’option -a (archive) et éventuellement -v (verbeux) si vous voulez pouvoir suivre l’avancement.


Si vous avez apprécié cet article, n’hésitez pas à laisser à son auteur un petit commentaire : il l’encouragera à le maintenir et à le développer.


Commentaires

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *