Sauvegarde Avec Rsync

Sommaire

Introduction

J’ai testé l’utilitaire “Active Backup” de mon NAS Synology depuis sa version bêta et il fonctionnait très bien (il fonctionne toujours d’ailleurs) pour la sauvegarde de mon serveur (VPS 🤥) chez OVH.
Depuis, j’ai ajouté un serveur chez moi pour mon système domotique et autres…
Depuis “Active Backup” est sortie de sa bêta en tant que “Active Backup for Business”.
J’ai donc lancé le logiciel pour ajouter mon nouveau serveur et là c’est le drame : il faut un compte Synology !
Pourquoi ? Je ne sais pas ! En tout cas, je ne vois pas pourquoi une entreprise (rappelons que c’est une version dite “business”) aurait l’intention de créer un compte et donc d’exposer ces données à Synology…

J’ai donc cherché une solution et je suis donc revenu aux bases avec Rsync !

rsync (pour remote synchronization ou synchronisation à distance), est un logiciel 1) de synchronisation de fichiers. Il est fréquemment utilisé pour mettre en place des systèmes de sauvegarde distante.
rsync travaille de manière unidirectionnelle c’est-à-dire qu’il synchronise, copie ou actualise les données d’une source (locale ou distante) vers une destination (locale ou distante) en ne transférant que les octets des fichiers qui ont été modifiés.
Documentation Rsync Ubuntu

J’ai donc effectué des recherches et tests afin de réaliser des sauvegardes avec les paramètres suivants :

  • Sauvegarde hebdomadaire de mes deux serveurs sur mon NAS
  • Création de snapshot de chacune des sauvegardes
  • Suppression automatique des anciennes sauvegardes
  • Notifications via un bot Telegram

Préparation

Mon NAS étant un Synology, j’ai la possibilité de m’y connecté en SSH afin d’effectuer des actions de type Linux.
Si cela n’est pas possible pour vous, je vous conseille de monter le partage sur un de vos serveurs et d’utiliser ce dernier pour effectuer les sauvegardes.

SSH

Mon NAS doit alors pouvoir se connecter en SSH sur mes serveurs sans passphrase, sinon rien ne saurais automatique (je ne songe surtout pas à renseigner la passphrase en clair dans mon script).
Pour cela, j’ai créé un utilisateur sur mon NAS (appelons le “MisterRsync”), je lui ai crée une paire de clés et j’ai sa clé publique sur mes deux serveurs pour que ce dernier puisse se connecter en root sur ces serveurs.
Afin que je puisse copier sans restrictions les fichiers de mes serveurs l’accès en root et forcement nécessaire

Répertoire de sauvegarde

J’ai donc créé un espace de stockage sur mon NAS dédié à cela et accessible uniquement par mon utilisateur “MisterRsync” (et les utilisateurs du groupe admin bien sûr).
J’ai d’ailleurs édité le fichier /etc/passwd afin que ce dossier soit le répertoire maison (je ne sais pas traduire “homedir” 😒).

Notifications

Pour les notifications, je souhaitais utiliser Telegram car c’est ce que j’utilise pour mes notifications Nagios et Home Assistant.
Cela est rendu possible grâce à Nicolas Bernaerts , une personne de la DSI de La Poste (🐔 !) !
Il a fait un script de notification Telegram sur Debian (qui fonctionne aussi sur Ubuntu et mon NAS), vous avez seulement besoin de cURL pour cela.

Pour l’installer, utiliser son script telegram-notify-install.sh disponible sur son GitHub ou taper simplement les commandes suivantes :

1
2
3
wget -O /etc/telegram-notify.conf https://raw.githubusercontent.com/NicolasBernaerts/debian-scripts/master/telegram/telegram-notify.conf
wget -O /usr/local/sbin/telegram-notify https://raw.githubusercontent.com/NicolasBernaerts/debian-scripts/master/telegram/telegram-notify
chmod +x /usr/local/sbin/telegram-notify

On le configure en éditant le fichier /etc/telegram-notify.conf avec le token et l’identifiant du groupe de notification.

Scripts de sauvegarde

Tests

Dans un premier temps, on va tester à la main que la sauvegarde fonctionne.
Pour ne pas perdre de temps (a attendre qu’on télécharge tous les fichiers), on va seulement faire une simulation du transfert grâce à l’option --dry-run de Rsync.

Pour cela je vous propose ici la commande que j’utilise :

1
2
3
rsync --archive --stats --human-readable --relative --delete --dry-run -e ssh \
root@192.168.92.17:{/etc,/home,/opt,/root,/usr/lib,/usr/local,/var/lib,/var/log,/var/www} \
/volume1/BackupStorage

Les antislashs sont là pour que la commande apparaisse sur plusieurs lignes.

Dont voici quelques explications :

  • –archive
    Mode archive : récursif, préserve les liens symboliques, les permissions … (voir les options rlptgoD pour une explication complète)
  • –stats
    Pour avoir des statistiques sur le transfert
  • –relative
    Pour avoir les fichiers en chemin relatif
  • –delete
    Supprime les fichiers qui n’existent plus sur la source dans le répertoire de destination
  • {dir1,dir2,…}
    Liste des répertoires à sauvegarder

Si cette commande fonctionne pour vos serveurs on peut passé à la suite.

Scripts

Le script ci-dessous et celui que j’ai fait pour effectuer la sauvegarde d’un serveur.
Il s’appelle selon l’usage ci-dessous :

backup.sh -S [Nom du serveur] -H [Nom d’hôte ou adresse IP] -b [Répertoire de sauvegarde] -d [Répertoire à sauvegarder]

Voici un exemple reprenant le test vu dans la partie Tests :

1
2
3
4
5
backup.sh \
-S MonServeur \
-H 192.168.92.17 \
-b "/volume1/BackupStorage" \
-d "/etc,/home,/opt,/root,/usr/lib,/usr/local,/var/lib,/var/log,/var/www" \

Le script en question :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#!/bin/bash
export LANG=en_US.UTF-8

# Handling options
while getopts "S:H:b:d:h" option
do
    case $option in
        S)
            SERVERNAME=$OPTARG
            ;;
        H)
            SERVERIP=$OPTARG
            ;;
        b)
            BACKUPSTR=$OPTARG
            ;;
        d)
            SERVERDIR=$OPTARG
            ;;
        h)
            echo    "Usage :"
            echo -n "$(basename $0) "
            echo -n "-S [Server Name] "
            echo -n "-H [Hostname or IP address] "
            echo -n "-b [Backup Storage] "
            echo -n "-d [Directories to Save] "
            echo    ""
            exit 0
            ;;
        :)
            echo "Argument needed for $OPTARG"
            exit 2
            ;;
        \?)
            echo "$OPTARG : invalid option"
            exit 3
            ;;
    esac
done

# Testing correct number of argument
if [ $# -ne 8 ]; then
    echo "Not right number of argument"
    echo "Use option '-h' for help"
    exit 1
fi

NOTIFY=$(which telegram-notify)

if [[ -z $NOTIFY ]]; then
    echo "Telegram Notification (telegram-notify) not available"
    exit 4
fi

DATE=$(date +%F)
BACKUPDIR="$BACKUPSTR/$SERVERNAME/backup"

mkdir -p $BACKUPDIR
if [ $? -ne 0 ]; then
    $NOTIFY --error --title "Error making $SERVERNAME backup" --text "Cannot create directory $BACKUPDIR"
    exit 5
fi


# Remove old backup log
rm -f $BACKUPDIR/backup-*.txt

# Telegram start notification
$NOTIFY --icon 25B6 --text "$SERVERNAME : Rsync started"

# Rsync (¬‿¬ )
rsync --archive --stats --human-readable --relative --delete -e ssh root@$SERVERIP:{$SERVERDIR} $BACKUPDIR | tee $BACKUPDIR/backup-$DATE.txt

# Telegram finished notification with rsync stats as attachement
$NOTIFY --success --text "$SERVERNAME : Rsync finished" --document "$BACKUPDIR/backup-$DATE.txt"
exit 0

Ce script va donc sauvegarder le répertoire spécifié dans l’option -d et les stocker dans un dossier portant le nom du serveur (option -S) dans le dossier de l’option -b.
Il créera aussi un fichier contenant le résultat du Rsync et me l’envoie en pièce jointe sur Telegram (cool non ?).
La ligne export LANG=en_US.UTF-8 m’est nécessaire afin de bien traduire les emojis de la notification Telegram.

Pour sauvegarder plusieurs serveurs, j’appelle ce script plusieurs fois via un autre script (backups.sh) :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#!/bin/bash

# MonServer backup
/volume1/BackupStorage/backup.sh \
-S MonServeur \
-H 192.168.92.17 \
-b "/volume1/BackupStorage" \
-d "/etc,/home,/opt,/root,/usr/lib,/usr/local,/var/lib,/var/log,/var/www" \

# LeMoinsChereDesVPSdOVH backup
/volume1/BackupStorage/backup.sh \
-S LeMoinsChereDesVPSdOVH \
-H www.scrample.xyz \
-b "/volume1/BackupStorage" \
-d "/etc,/root,/usr/lib,/usr/local,/var/lib,/var/log,/var/www" \

J’ai donc maintenant une solution de sauvegarde de mon serveur.
Mais admettons que je souhaite remettre en place mon serveur dans un état antérieur à la dernière sauvegarde. Avec simplement cela, je ne peux pas le faire !
J’ai donc mis en place en parallèle une solution de snapshot.

Scripts de snapshot

Le principe est de faire une archive du dossier sauvegardé de manière régulière.
Si je lance la sauvegarde tous les jours et que je fais un snapshot toutes les semaines, en cas de problème, je peux revenir au dernier snapshot plutôt qu'à la dernière sauvegarde.

Le script ci-dessous et celui que j’ai fait pour cela.
Il s’appelle selon l’usage ci-dessous :

snapshot.sh -S [Nom du serveur] -b [Nom du serveur]

Voici un exemple d’application :

1
backup.sh -S MonServeur -b "/volume1/BackupStorage"

Le script en question :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#!/bin/bash
export LANG=en_US.UTF-8

# Handling options
while getopts "S:b:h" option
do
    case $option in
        S)
            SERVERNAME=$OPTARG
            ;;
        b)
            BACKUPSTR=$OPTARG
            ;;
        h)
            echo    "Usage :"
            echo -n "$(basename $0) "
            echo -n "-S [Server Name] "
            echo -n "-b [Backup Storage] "
            echo    ""
            exit 0
            ;;
        :)
            echo "Argument needed for $OPTARG"
            exit 2
            ;;
        \?)
            echo "$OPTARG : invalid option"
            exit 3
            ;;
    esac
done

# Testing correct number of argument
if [ $# -ne 4 ]; then
    echo "Not right number of argument"
    echo "Use option '-h' for help"
    exit 1
fi


NOTIFY=$(which telegram-notify)

if [[ -z $NOTIFY ]]; then
    echo "Telegram Notification (telegram-notify) not available"
    exit 4
fi

BACKUPDIR="$BACKUPSTR/$SERVERNAME/backup"
SNAPDIR="$BACKUPSTR/$SERVERNAME/snapshot"

# Test if the backup directory exist
if [ ! -d $BACKUPDIR ]; then
    $NOTIFY --error --title "Error making $SERVERNAME snapshot" --text "Directory $BACKUPDIR does not exist" 
    exit 5
	fi

# Find backup stats file (stop at first result : should be only one)
BACKUPFILE=$(find $BACKUPDIR -type f -name backup-*.txt -print -quit)

# Test if the backup file exist
if [ -z "$BACKUPFILE" ]; then
    $NOTIFY --error --title "Error making $SERVERNAME snapshot" --text "Backup file in $BACKUPDIR does not exist"
    exit 6
fi

# Get the date of the backup (written in the file name)
DATE=$(basename $BACKUPFILE | cut -d'-' -f2- | cut -d'.' -f1)

# Telegram start notification
$NOTIFY --icon 25B6 --text "Making $SERVERNAME snapshot of $DATE backup"

mkdir -p $SNAPDIR
cd $BACKUPDIR
tar --warning='no-file-ignored' -czf $SNAPDIR/snapshot-$DATE.tgz *
if [ $? -ne 0 ]; then
    $NOTIFY --error --title "Error making $SERVERNAME snapshot" --text "Tar task for $BACKUPDIR of $DATE failed"
    exit 7
fi

TARFILESIZE=$(du -h $SNAPDIR/snapshot-$DATE.tgz | awk '{print $1}')

# Telegram finished notification with rsync stats as attachement
$NOTIFY --success --text "$SERVERNAME snapshot of $DATE completed with a file of $TARFILESIZE"

# Delete old backup
find $SNAPDIR -mtime +60 -type f -exec rm -f '{}' \;

exit 0

Ce script va donc créer une archive pour la dernière sauvegarde du serveur dont le nom est spécifié via l’option -S en utilisant le fichier de log contenu dans le dossier de sauvegarde (option -b).
La notification Telegram inclut la taille du snapshot.
Ce script fait aussi du nettoyage car il supprime les snapshots qui ont été créées il y a plus de 60 jours.

Comme pour les backups, pour effectuer cet action sur les sauvegardes de plusieurs serveurs, j’appelle ce script plusieurs fois via un autre script (snapshots.sh) :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#!/bin/bash

# MonServeur snapshot
/volume1/BackupStorage/snapshot.sh \
-S MonServeur \
-b "/volume1/BackupStorage" \

# LeMoinsChereDesVPSdOVH snapshot
/volume1/BackupStorage/snapshot.sh \
-S LeMoinsChereDesVPSdOVH \
-b "/volume1/BackupStorage" \

Note : L’archive ne contient plus les fichiers sockets présents (mais inutile) de la sauvegarde.

Automatisation

Afin d’automatiser cela, j’ai ajouté deux tâches programmées sur mon NAS :

  • Une qui exécute backups.sh tous les mardis via l’utilisateur “MisterRsync”
  • Une qui exécute snapshots.sh tous les mercredis via l’utilisateur “root” (nécessaire à cause des droits de certains fichiers)