Auto-hébergment : mon système de sauvegarde
La sauvegarde est un élément très important dans l'auto-hébergement. On oublie la sauvegarde, ça crash, on a plus rien...
Pendant
quelques semaines après avoir mis en place mon auto-hébergement, je
n'avais toujours qu'un seul disque dur dans mon serveur, je lui faisais
confiance :)
Et puis j'ai eu un petit problème sur un serveur au boulot, problème qui a miraculeusement été résolu grâce à une sauvegarde efficace. Je me suis donc décidé à investir un peu de mon temps dans la sauvegarde de mon serveur perso.
Le boitier de mon serveur permet d'accueillir deux disques dur format 2"1/5. Le premier étant utilisé pour mon système, j'ai décidé d'en ajouter un deuxième et de répliquer les données du premier dessus.J'aurai pu choisir de mettre en place un système de RAID1 entre les deux disques mais j'ai préféré opter pour une synchronisation d'un disque vers l'autre plusieurs fois par semaine. Cela me permet de revenir en arrière si besoin. Par exemple, je fais une mise à jour qui se passe mal ou j'écrase un fichier involontairement. Je peux facilement récupérer la configuration ou le fichier de la veille, stocké sur mon deuxième disque, chose qui aurait été impossible en RAID1.
J'ai organisé ma sauvegarde en deux étapes : la base de données MySQL et les répertoires/fichiers de mon système.
Sauvegarde des bases de données
J'ai écrit un script bash qui me permet de faire des dumps de mes bases de données :
#!/bin/sh
#
# Il faut que le user dump ait un droit general de SELECT et RELOAD
MYSQL_BIN_PATH=/usr/bin
MYSQL_DATA_PATH=/var/lib/mysql
MYSQL_HOME=/mysql
FIC_ERR=$MYSQL_HOME/dump/erreur.txt
HOSTNAME=`hostname`
SYSTEME="mail@me.fr"
USER=dump
PASSWD="xxdumpxx"
/bin/rm $MYSQL_HOME/dump/*
LISTE_BASES=`/usr/bin/find $MYSQL_DATA_PATH/* -maxdepth 0 -type d -printf "%f\\n" `
for DB in $LISTE_BASES
do
DATABASE=`echo $DB | sed 's/@002d/-/'`
echo base $DATABASE
$MYSQL_BIN_PATH/mysqldump -u $USER --password=$PASSWD --opt --databases --result-file $MYSQL_HOME/dump/$DATABASE.dump $DATABASE 2>>$FIC_ERR
RET=$?
RETOUR=`expr $RETOUR + $RET`
if [ $RET -gt 0 ]
then
MESSAGE="$MESSAGE Erreur de dump de la base $DATABASE\\n"
fi
/bin/gzip $MYSQL_HOME/dump/$DATABASE.dump
done
/bin/chmod -R 600 $MYSQL_HOME/dump
/bin/chmod -R 700 $MYSQL_HOME/dump*
if [ $# -gt 0 ] && [ $RETOUR -gt 0 ]
then
echo $MESSAGE | /bin/mail -s "mysql sur $HOSTNAME. Erreur dump des bases" $SYSTEME
fi
Ce script va interroger le nom de mes différentes bases de données stockées sur mon serveur et en fait un dump séparé. Au final, j'obtiens un répertoire /mysql/dump/ qui contiendra les différents dumps de mes différentes bases de données.
Note : L'utilisateur qui fera le dump doit avoir les droits de SELECT, RELOAD et LOCK TABLES sur les bases de données.
Sauvegarde des répertoires/fichiers de mon serveur
Une fois mes bases de données sauvegardées, je vais copier tous les fichiers importants sur le deuxième disque dur. Pour cela, j'utilise rsync :
#!/bin/bash
# $? = code de retour de la dernière commande. 0 si pas de problème
# on additionne les codes de retour à chaque fin de chaque commande, si ça dépasse 0, c'est qu'il y a eu une erreur quelque part
/bin/bash /scripts/dump_mysql.sh
FICHIER_LOG="/scripts/backup_rsync.log"
/bin/rm $FICHIER_LOG
/usr/bin/touch $FICHIER_LOG
echo "*****************************************************************" >> $FICHIER_LOG
/bin/date >> $FICHIER_LOG
echo "*************Dump MySQL *************" >> $FICHIER_LOG
/usr/bin/rsync -rlpgotD --stats --delete --force /mysql/ /backup/mysql/ >> $FICHIER_LOG
RET=$?
RETOUR=`expr $RETOUR + $RET`
echo "*************Configuration Apache /etc/apache2 *************" >> $FICHIER_LOG
/usr/bin/rsync -rlpgotD --stats --delete --force /etc/apache2/ /backup/etc/apache2/ >> $FICHIER_LOG
RET=$?
RETOUR=`expr $RETOUR + $RET`
echo "*********************Home /home/*********************" >> $FICHIER_LOG
/usr/bin/rsync -rlpgotD --stats --delete --force /home/ /backup/home/ >> $FICHIER_LOG
RET=$?
RETOUR=`expr $RETOUR + $RET`
/bin/date >> $FICHIER_LOG
RET=$?
RETOUR=`expr $RETOUR + $RET`
echo "*****************************************************************" >> $FICHIER_LOG
if [ $RETOUR -ne 0 ]
then
echo "Le script de rsync a echoue. Code erreur : "$RETOUR | /usr/bin/mail -s "Erreur script rsync" mail@me.fr
fi
Ce script va faire une sauvegarde (miroir) des répertoires /home/, /mysql/ et /etc/apache2/ vers /backup/home/, /backup/mysql/ et /backup/etc/apache2. /backup étant le point de montage de mon disque de sauvegarde.
Voici une explication des arguments de rsync :
-
rsync : appelle le programme rsync
-
-r : parcours le dossier indiqué et tous ses sous-dossiers
-
-l : copie les liens symboliques comme liens symboliques
-
-t : préserve les dates
-
-g : préserve le groupe
-
-o : mettre le propriétaire du fichier de destination identique à celui du fichier source
-
-D : préserve les périphériques
-
-p : provoque la mise à jour des permissions sur la destination pour qu'elles soient identiques aux permissions sur la source.
-
--force : force la suppression de répertoires même non-vides
-
--stats : affiche quelques statistiques de transfert de fichiers, ce qui permet de vérifier l'efficacité de la sauvegarde.
- --delete : efface avant le transfert les fichiers qui n'existent pas sur la source.
Automatisation de la sauvegarde
Je n'ai plus qu'à appeler le script ci-dessus à la fréquence à laquelle je souhaite faire mes sauvegardes dans le cron. Voici ma crontab :30 23 * * 1,4,6 /root/scripts/backup_rsync.sh >/dev/null 2>&1
Ainsi, tous les lundis, jeudis et samedi à 23h30, je sauvegarde les répertoires importants de mon disque 1 vers mon disque 2.
Bonus
Je fais également une sauvegarde de mes bases de données et de mon répertoire www sur une clé USB une fois par mois avec ce script :#!/bin/bash
# $? = code de retour de la dernière commande. 0 si pas de problème
# on additionne les codes de retour à chaque fin de chaque commande, si ça dépasse 0, c'est qu'il y a eu une erreur quelque part
MAIL_CONTACT='mail@gmail.com'
FICHIER_LOG="/root/scripts/logs/backup_usb.log"
REP_DEST="/mnt/usb/`date +%d%m%Y`"
/bin/rm $FICHIER_LOG
/usr/bin/touch $FICHIER_LOG
/bin/mount /dev/sdc1 /mnt/usb/
/bin/rm -rf /mnt/usb/*
/bin/mkdir $REP_DEST
echo "*****************************************************************" >> $FICHIER_LOG
/bin/date >> $FICHIER_LOG
echo "*************Copie des répertoires /mysql *************" >> $FICHIER_LOG
/bin/cp -pr /mysql/ $REP_DEST
RET=$?
RETOUR=`expr $RETOUR + $RET`
echo "*************Copie du répertoire /www *************" >> $FICHIER_LOG
/bin/cp -pr /www/ $REP_DEST
RET=$?
RETOUR=`expr $RETOUR + $RET`
/bin/date >> $FICHIER_LOG
RET=$?
RETOUR=`expr $RETOUR + $RET`
echo "*****************************************************************" >> $FICHIER_LOG
if [ $RETOUR -ne 0 ]
then
echo "Le script de backup USB a echoue. Code erreur : "$RETOUR | /usr/bin/mail -s "Erreur script backup USB" $MAIL_CONTACT
fi
/bin/umount /mnt/usb/
Si vous cherchiez des pistes pour sauvegarder votre serveur, j'espère vous avoir un peu éclairé.
Comme toujours, si vous avez des suggestions à me proposer ou si vous souhaitez des précisions supplémentaires sur ces scripts, n'hésitez pas à demander.
Par ailleurs, je serais curieux de connaitre vos moyens de sauvegarde en auto-hébergement :)