Sauvegarde régulière de la config docker et de mes scripts
Author: Unknown
Date: 19/07/2025
J'ai commencé à faire pas mal de choses, et je me voudrais de tout perdre si le serveur a un problème. Dans un premier temps, je vais déjà faire une sauvegarde de ce que je fais sur le disque dur externe USB branché sur mon serveur, avec des sauvegardes incrémentales permettant de remonter à un an avec une précision de un mois et sur une semaine avec une précision de un jour.
Élaboration du script
Histoire d'alléger l'écriture du script, et d'éviter de passer à côté d'une erreur crachée sur la sortie standard par oubli d'un rajout de 2>&1, je rajoute une redirection globale au début de mon script:
mkdir -p "$LOGDIR"
exec >> "$LOGFILE" 2>&1
Et comme c'est plus pratique de tout avoir en sortie à l'écran pendant qu'on élabore le script, je rajoute un mode debug:
# Mode debug: 1 pour activer, 0 pour désactiver
DEBUG_MODE=0
if [ "$DEBUG_MODE" -eq 0 ]
then
# En mode normal, tout dans le fichier uniquement
mkdir -p "$LOGDIR"
exec >> "$LOGFILE" 2>&1
fi
Je crée une fonction de log pour bien logguer de manière homogène, avec le nom du script et la date/heure.
# Fonction de log
function log {
echo "$(date '+%Y%m%d.%H%M%S')|$0|$1"
}
Enfin, je me crée une fonction qui permet de vérifier le code erreur de la dernière commande, et log différemment suivant qu'il s'agit d'un échec ou d'un succès:
# Fonction pour vérifier le statut
function check_status {
local status=$1
local msg_success=$2
local msg_failure=$3
if [ "$status" -eq 0 ]; then
log "$msg_success"
return 0
else
log "$msg_failure|error code=$status"
exit "$status"
fi
}
Fonction qui s'appelle par exemple ainsi:
rsync avec_plein_de_paramètres
exit_code=$?
check_status $exit_code "Sync for $SUBDIR completed successfully" "Sync for $SUBDIR failed with exit code $exit_code"
La gestion incrémentale est un peu bourrin, mais au moins c'est compréhensible:
# Décalage des sauvegardes
if [ "$(date '+%d')" -eq 1 ]
then
log "Monthly backup"
rm -fr $DEST/monthly.11/$SUBDIR
mv $DEST/monthly.10/$SUBDIR $DEST/monthly.11/$SUBDIR
mv $DEST/monthly.09/$SUBDIR $DEST/monthly.11/$SUBDIR
mv $DEST/monthly.08/$SUBDIR $DEST/monthly.09/$SUBDIR
mv $DEST/monthly.07/$SUBDIR $DEST/monthly.08/$SUBDIR
mv $DEST/monthly.06/$SUBDIR $DEST/monthly.07/$SUBDIR
mv $DEST/monthly.05/$SUBDIR $DEST/monthly.06/$SUBDIR
mv $DEST/monthly.04/$SUBDIR $DEST/monthly.05/$SUBDIR
mv $DEST/monthly.03/$SUBDIR $DEST/monthly.04/$SUBDIR
mv $DEST/monthly.02/$SUBDIR $DEST/monthly.03/$SUBDIR
mv $DEST/monthly.01/$SUBDIR $DEST/monthly.02/$SUBDIR
mv $DEST/monthly.00/$SUBDIR $DEST/monthly.01/$SUBDIR
mv $DEST/daily.7/$SUBDIR $DEST/monthly.00/$SUBDIR
else
rm -fr $DEST/daily.7/$SUBDIR
fi
mv $DEST/daily.6/$SUBDIR $DEST/daily.7/$SUBDIR
mv $DEST/daily.5/$SUBDIR $DEST/daily.6/$SUBDIR
mv $DEST/daily.4/$SUBDIR $DEST/daily.5/$SUBDIR
mv $DEST/daily.3/$SUBDIR $DEST/daily.4/$SUBDIR
mv $DEST/daily.2/$SUBDIR $DEST/daily.3/$SUBDIR
mv $DEST/daily.1/$SUBDIR $DEST/daily.2/$SUBDIR
mv $DEST/daily.0/$SUBDIR $DEST/daily.1/$SUBDIR
Évidemment, il faut qu'aucune erreur n'arrive, sinon le script s'arrête. Donc, impossible d'avoir des "erreurs normales". Dans mon cas, le rsync -a --delete --link-dest=$DEST/daily.1/$SUBDIR /home/user/$SUBDIR $DEST/daily.0/$SUBDIR n'arrivait pas à copier les fichiers de clés pour des problèmes de droit. Ces fichiers de clé étant générés par letsencrypt, j'en aurais besoin pour un backup de type PRA, mais là, il s'agit juste d'éviter de repartir à zéro, donc je peux m'en passer. L'ajout de --exclude='\*.pem' permet de résoudre le problème.
L'argument --link-dest demande de faire des hardlink quand le fichier n'a pas changé. Cela permet d'éviter de faire de perdre de l'espace disque inutilement.
Le script final:
#!/bin/bash
# Définir directement le nom du fichier de log avec l'année et le mois
LOGDIR="/var/log/backup"
LOGFILE="$LOGDIR/backup_$(date '+%Y-%m').log"
# Mode debug: 1 pour activer, 0 pour désactiver
DEBUG_MODE=0
# Fonction de log
function log {
echo "$(date '+%Y%m%d.%H%M%S')|$0|$1"
}
# Fonction pour vérifier le statut
function check_status {
local status=$1
local msg_success=$2
local msg_failure=$3
if [ "$status" -eq 0 ]; then
log "$msg_success"
return 0
else
log "$msg_failure|error code=$status"
exit "$status"
fi
}
if [ "$DEBUG_MODE" -eq 0 ]
then
# En mode normal, tout dans le fichier uniquement
mkdir -p "$LOGDIR"
exec >> "$LOGFILE" 2>&1
fi
# Début du script
log ""
log "##################################################################"
log "Script: $0"
log "Arguments: $@"
log "Started"
global_exit_code=0
# Exécuter rsync et journaliser les sorties et les erreurs DEST=/mnt/linux/PERSONNEL/SERVER/backup/lnxsrv/home_user
mkdir -p $DEST/daily.0 $DEST/daily.1 $DEST/daily.2 $DEST/daily.3 $DEST/daily.4 $DEST/daily.5 $DEST/daily.6 $DEST/daily.7
mkdir -p $DEST/monthly.00 $DEST/monthly.01 $DEST/monthly.02 $DEST/monthly.03 $DEST/monthly.04 $DEST/monthly.05 $DEST/monthly.06 $DEST/monthly.07 $DEST/monthly.08 $DEST/monthly.09 $DEST/monthly.10 $DEST/monthly.11
for SUBDIR in docker noteblogger scripts
do
# Décalage des sauvegardes
if [ "$(date '+%d')" -eq 1 ]
then
log "Monthly backup"
rm -fr $DEST/monthly.11/$SUBDIR
mv $DEST/monthly.10/$SUBDIR $DEST/monthly.11/$SUBDIR
mv $DEST/monthly.09/$SUBDIR $DEST/monthly.11/$SUBDIR
mv $DEST/monthly.08/$SUBDIR $DEST/monthly.09/$SUBDIR
mv $DEST/monthly.07/$SUBDIR $DEST/monthly.08/$SUBDIR
mv $DEST/monthly.06/$SUBDIR $DEST/monthly.07/$SUBDIR
mv $DEST/monthly.05/$SUBDIR $DEST/monthly.06/$SUBDIR
mv $DEST/monthly.04/$SUBDIR $DEST/monthly.05/$SUBDIR
mv $DEST/monthly.03/$SUBDIR $DEST/monthly.04/$SUBDIR
mv $DEST/monthly.02/$SUBDIR $DEST/monthly.03/$SUBDIR
mv $DEST/monthly.01/$SUBDIR $DEST/monthly.02/$SUBDIR
mv $DEST/monthly.00/$SUBDIR $DEST/monthly.01/$SUBDIR
mv $DEST/daily.7/$SUBDIR $DEST/monthly.00/$SUBDIR
else
rm -fr $DEST/daily.7/$SUBDIR
fi
mv $DEST/daily.6/$SUBDIR $DEST/daily.7/$SUBDIR
mv $DEST/daily.5/$SUBDIR $DEST/daily.6/$SUBDIR
mv $DEST/daily.4/$SUBDIR $DEST/daily.5/$SUBDIR
mv $DEST/daily.3/$SUBDIR $DEST/daily.4/$SUBDIR
mv $DEST/daily.2/$SUBDIR $DEST/daily.3/$SUBDIR
mv $DEST/daily.1/$SUBDIR $DEST/daily.2/$SUBDIR
mv $DEST/daily.0/$SUBDIR $DEST/daily.1/$SUBDIR
log "rsync -a --delete --exclude='*.pem' --link-dest=$DEST/daily.1/$SUBDIR /home/user/$SUBDIR $DEST/daily.0/$SUBDIR"
rsync -a --delete --exclude='*.pem' --link-dest=$DEST/daily.1/$SUBDIR /home/user/$SUBDIR $DEST/daily.0/$SUBDIR
exit_code=$?
# Vérifier le code de sortie de rsync pour déterminer le succès ou l'échec
check_status $exit_code "Sync for $SUBDIR completed successfully" "Sync for $SUBDIR failed with exit code $exit_code"
done
log "Sync completed successfully"
log "End"
log "##################################################################"
log ""
Tout le reste à faire autour du script
Script de synchro
- Tout d'abord:
cd
mkdir -p scripts
cd scripts
vi backup.bash
- Le backup.bash à recopier dans vi
- Puis:
chmod +x backup.bashsudo mkdir -p /var/log/backupsudo chmod a+rwx /var/log/backup
Synchro en crontab
crontab -e56 20 * * * /home/user/scripts/backup.bash
Vérification
Quelques jours plus tard, je vérifie et le job n'a pas l'air d'avoir tourné.
Le log du script /var/log/backup n'a pas bougé d'un poil. Pourtant, le fichier de log a les mêmes droits que celui dans /var/log/sync_nas, où tout se passe bien. Au passage, je découvreque le montage de /mnt/nas_pctv_ro n'est plus là. Encore un truc à vérifier régulièrement via un traitement dédié.
Un coup d'oeil dans /var/log/syslog montre que la crontab a bien lancé le script:
user@lnxsrv:/var/log$ grep backup.bash syslog
2025-07-18T20:56:01.973478+00:00 lnxsrv CRON[132139]: (user) CMD (/home/user/scripts/backup.bash)
Je change la périodicité de la crontab pour essayer de mieux comprendre: 0,5,10,15,20,25,30,35,40,45,50,55 * * * * /home/user/scripts/backup.bash
J'essaye de comparer le script qui fonctionne et celui qui ne fonctionne pas:
user@lnxsrv:/var/log$ ls -ald sync_nas backup
drwxrwxrwx 2 root root 4096 juil. 17 22:02 backup
drwxrwxrwx 2 root root 4096 juil. 12 03:33 sync_nas
user@lnxsrv:/var/log$ ls -al sync_nas backup
backup:
total 12
drwxrwxrwx 2 root root 4096 juil. 17 22:02 .
drwxrwxr-x 12 root syslog 4096 juil. 17 21:05 ..
-rw-rw-r-- 1 user user 3409 juil. 17 22:03 backup_2025-07.log
sync_nas:
total 152
drwxrwxrwx 2 root root 4096 juil. 12 03:33 .
drwxrwxr-x 12 root syslog 4096 juil. 17 21:05 ..
-rw-rw-r-- 1 user user 110293 juin 30 03:38 sync_nas_2025-06.log
-rw-rw-r-- 1 user user 25390 juil. 19 03:33 sync_nas_2025-07.log
Côté droits, cela parait identique.
Je vois quand même que le fichier de log date du 17 juillet à 22;03 alors que syslog indique que /home/user/scripts/backup.bash a été lancé le 18 juillet à 20h56. je vérifie s'il n'y a pas un problème de droits au niveau des scripts:
user@lnxsrv:/var/log$ ls -l /home/user/scripts/synchro_pctv_personnel_to_local.bash /home/user/scripts/backup.bash
ls: cannot access '/home/user/scripts/backup.bash': No such file or directory
-rwxrwxr-x 1 user user 1936 juin 20 16:25 /home/user/scripts/synchro_pctv_personnel_to_local.bash
OK, PEBCAK, je me suis planté dans le nom du script. Je change le suffixe de mon script:
user@lnxsrv:/var/log$ mv /home/user/scripts/backup.sh /home/user/scripts/backup.bash
Cette fois-ci, cela fonctionne correctement:
user@lnxsrv:/var/log$ ll backup/backup_2025-07.log
-rw-rw-r-- 1 user user 5310 juil. 19 12:30 backup/backup_2025-07.log
user@lnxsrv:/var/log$ tail backup/backup_2025-07.log
20250719.123001|/home/user/scripts/backup.bash|Sync for docker completed successfully
20250719.123001|/home/user/scripts/backup.bash|rsync -a --delete --exclude='*.pem' --link-dest=/mnt/linux/PERSONNEL/SERVER/backup/lnxsrv/home_user/daily.1/noteblogger /home/user/noteblogger /mnt/linux/PERSONNEL/SERVER/backup/lnxsrv/home_user/daily.0/noteblogger
20250719.123001|/home/user/scripts/backup.bash|Sync for noteblogger completed successfully
20250719.123001|/home/user/scripts/backup.bash|rsync -a --delete --exclude='*.pem' --link-dest=/mnt/linux/PERSONNEL/SERVER/backup/lnxsrv/home_user/daily.1/scripts /home/user/scripts /mnt/linux/PERSONNEL/SERVER/backup/lnxsrv/home_user/daily.0/scripts
20250719.123001|/home/user/scripts/backup.bash|Sync for scripts completed successfully
20250719.123001|/home/user/scripts/backup.bash|Sync completed successfully
20250719.123001|/home/user/scripts/backup.bash|End
20250719.123001|/home/user/scripts/backup.bash|##################################################################
20250719.123001|/home/user/scripts/backup.bash|##################################################################
20250719.123001|/home/user/scripts/backup.bash|
Re re vérification
Au passage suivant de la crontab, après avoir en plus modifié un des éléments sauvegardés, j'ai bien des jolis logs:
user@lnxsrv:/var/log$ tail -15 /var/log/backup/backup_2025-07.log
20250719.124001|/home/user/scripts/backup.bash|
20250719.124001|/home/user/scripts/backup.bash|##################################################################
20250719.124001|/home/user/scripts/backup.bash|Script: /home/user/scripts/backup.bash
20250719.124001|/home/user/scripts/backup.bash|Arguments:
20250719.124001|/home/user/scripts/backup.bash|Started
20250719.124001|/home/user/scripts/backup.bash|rsync -a --delete --exclude='*.pem' --link-dest=/mnt/linux/PERSONNEL/SERVER/backup/lnxsrv/home_user/daily.1/docker /home/user/docker /mnt/linux/PERSONNEL/SERVER/backup/lnxsrv/home_user/daily.0/docker
20250719.124001|/home/user/scripts/backup.bash|Sync for docker completed successfully
20250719.124001|/home/user/scripts/backup.bash|rsync -a --delete --exclude='*.pem' --link-dest=/mnt/linux/PERSONNEL/SERVER/backup/lnxsrv/home_user/daily.1/noteblogger /home/user/noteblogger /mnt/linux/PERSONNEL/SERVER/backup/lnxsrv/home_user/daily.0/noteblogger
20250719.124001|/home/user/scripts/backup.bash|Sync for noteblogger completed successfully
20250719.124001|/home/user/scripts/backup.bash|rsync -a --delete --exclude='*.pem' --link-dest=/mnt/linux/PERSONNEL/SERVER/backup/lnxsrv/home_user/daily.1/scripts /home/user/scripts /mnt/linux/PERSONNEL/SERVER/backup/lnxsrv/home_user/daily.0/scripts
20250719.124001|/home/user/scripts/backup.bash|Sync for scripts completed successfully
20250719.124001|/home/user/scripts/backup.bash|Sync completed successfully
20250719.124001|/home/user/scripts/backup.bash|End
20250719.124001|/home/user/scripts/backup.bash|##################################################################
20250719.124001|/home/user/scripts/backup.bash|
J'aime bien ces lignes de ################################# cela rappelle quand je faisais cela gamin dans les commentaires de mes programmes en GFA Basic sur Atari ;-)
Et la sauvegarde incrémentale me permet bien de voir ma modification:
user@lnxsrv:/mnt/linux/PERSONNEL/SERVER/backup/lnxsrv/home_user$ diff -r daily.0/scripts/ daily.1/scripts/
diff -r daily.0/scripts/scripts/backup.bash daily.1/scripts/scripts/backup.bash
39a40
> log "##################################################################"
80d80
< exit_code=$?
82c82
< check_status $exit_code "Sync for $SUBDIR completed successfully" "Sync for $SUBDIR failed with exit code $exit_code"
---
> check_status $? "Sync for $SUBDIR completed successfully" "Sync for $SUBDIR failed with exit code $exit_code"
86a87
> log "##################################################################"
Améliorations possibles
La rotation journalière est en fait une rotation à chaque exécution. Elle n'est journalière que si le script n'est exécutée qu'une fois par jour.
La suite:
J'aimerais également:
- une génération régulière des mes blogs
- remonter le disque dur externe si démonté-je-ne-sais-pas-pourquoi
- remonter le partage du nas si démonté-je-ne-sais-pas-pourquoi
- un redémarrage automatique des containers en cas de reboot du serveur
- un suivi / admin web docker (https://github.com/henrygd/beszel?tab=readme-ov-file?)
- une centralisation des logs apaches docker et les interroger via Matomo
- installer une gallerie photo++ style photoprism
- une centralisation des logs docker et les interroger via un ELK
- une centralisation des logs locaux et les interroger via un ELK
- vérifier que la sauvegarde mensuelle fonctionne
- une centralisation de certains logs distants et les interroger via un ELK
- sortir les éventuels password des fichiers de configuration
Tags: computing ubuntu serveur-bayart back2code informatique article mon-serveur-à-moi-qui-me-va-bien