LAMP : Sauvegarder facilement ses sites web

Sunday, January 13, 2013

Un mini article où je vous propose des scripts pour sauvegarder vos sites web du type PHP+MySQL. C’est toujours plus simple et plus rapide de restaurer depuis des fichiers sur le système plutôt que de faire appel à des outils plus lourd tel que Time Navigator, TSM ou autre. Dans la suite, vous trouverez les scripts ainsi que la doc d’installation de ces derniers.

Préparation

On va créer deux dossiers, un pour les scripts, l’autre pour les sauvegardes. Pour ma part, ces deux dossiers se trouvent dans /root. Suivant comment vous avez partionné votre système, vous pouvez adapter les chemin.

Création de l’arborescence :

cd /root
mkdir scripts
mkdir -p save/www
mkdir -p save/mysql

Script de sauvegarde des fichiers

Ce premier script ne s’occupe de sauvegarder que les fichiers d’un site web, c’est à dire le document root d’un vhost. Si vous avez suivi mon article de configuration Apache, les fichiers pour un vhost spécifique se trouve dans /var/www//. Le script crée une archive en tar.gz et effectue une rotation pour garder les N dernières sauvegardes. Enfin, il log dans un fichier dédié.

Le script save_www.sh

Ce script crée une archive tar.gz d’un répertoire dans /var/www, puis il fait une rotation de ces archives tar.gz afin de conserver un historique de N jours.

On crée le fichier :

vim /root/scripts/save_www.sh

Copiez collez le script suivant :

#!/bin/bash

# Parametres dossiers
www_root="/var/www"
save_root="/root/save/www"
script_root="/root/scripts"
# Parametres fichiers
www_filter="$script_root/save_www.filter"
www_list="$script_root/save_www.list"
save_error="/root/script.error"
save_log="/var/log/save_www.log"

# On se place dans www_root
cd $www_root

for www_site in `cat "$www_list"`
do
        # Archivage fichiers du site
        debug=`tar zcvfh "$save_root/$www_site.tar.gz.tmp" "$www_site" --exclude-from "$www_filter"`

        # Check reussite commande TAR
        if [[ $? -ge "1" ]]
        then
                # Commande echouee
                echo "`date +%d/%m/%y-%H:%M:%S` : Erreur sauvegarde du site $www_site" >> "$save_log"
                rm "$save_root/$www_site.tar.gz.tmp"
                echo "$debug" > $save_error
                exit
        fi

        # Rotation des archives
        for (( i=8; i>0; i-- ))
        do
                # L'archive precedente
                j=`expr $i - 1`
                if [[ $j -ge "1" ]]
                then
                        # Check archive existe
                        if [[ -e "$save_root/$www_site.tar.gz.$j" ]]
                        then
                                # La premiere archive ne s'appelle pas .tar.gz.0
                                debug=`mv "$save_root/$www_site.tar.gz.$j" "$save_root/$www_site.tar.gz.$i"`
                                # Check reussite commande MV
                                if [[ $? -ge "1" ]]
                                then
                                        # Commande echouee
                                        echo "`date +%d/%m/%y-%H:%M:%S` : Erreur mv $www_site.tar.gz.$j vers $www_site.tar.gz.$i" >> "$save_log"
                                        echo "$debug" > $save_error
                                        exit
                                fi
                        fi
                else
                        # Check archive existe
                        if [[ -e "$save_root/$www_site.tar.gz" ]]
                        then
                                debug=`mv "$save_root/$www_site.tar.gz" "$save_root/$www_site.tar.gz.$i"`
                                # Check reussite commande MV
                                if [[ $? -ge "1" ]]
                                then
                                        # Commande echouee
                                        echo "`date +%d/%m/%y-%H:%M:%S` : Erreur mv $www_site.tar.gz vers $www_site.tar.gz.$i" >> "$save_log"
                                        echo "$debug" > $save_error
                                        exit
                                fi
                        fi
                fi
        done
       
        # Nouvelle archive
        debug=`mv "$save_root/$www_site.tar.gz.tmp" "$save_root/$www_site.tar.gz"`
        # Check reussite commande MV
        if [[ $? -ge "1" ]]
        then
              # Commande echouee
              echo "`date +%d/%m/%y-%H:%M:%S` : Erreur mv $www_site.tar.gz.tmp vers $www_site.tar.gz" >> "$save_log"
              echo "$debug" > $save_error
              exit
        fi

        # Taille nouvelle archive
        size_site=`du -hs $save_root/$www_site.tar.gz | awk '{ print $1 }'`

        # Log l'archivage
        echo "`date +%d/%m/%y-%H:%M:%S` : Sauvegarde du site $www_site [$size_site]" >> "$save_log"

done

# Permissions sur archives
cd $save_root
chmod 400 *

Pensez à ajouter les droits d’exécution :

chmod 754 /root/scripts/save_www.sh

Le fichier save_www.list

Ce fichier liste les sites à sauvegarder. Je considère que chaque site à son propre répertoire dans /var/www. Il suffit de mettre le nom du répertoire pour qu’il soit sauvegarder. Un nom par ligne séparé par un retour chariot.

On crée le fichier :

vim /root/scripts/save_www.list

Exemple de fichier :

blog
wiki
galerie

Le fichier save_www.filter

Ce fichier liste les extensions de fichiers qui ne seront pas sauvegardées. J’exclue en général les .mp3 et les .avi qui peuvent peser très très lourd. A ajuster en fonction de votre besoin et de votre volumétrie.

On crée le fichier :

vim /root/scripts/save_www.filter

Exemple de fichier :

*.mp3
*.MP3
*.avi
*.AVI

Mise en place du cron

On édite la crontab :

crontab -e

On ajoute cette ligne :

# Sauvegarde WWW
0 0 * * * bash /root/scripts/save_www.sh > /dev/null

Rotation des logs

Le script écrit un événement dans un journal à chaque sauvegarde. On va utiliser logrotate.d pour s’assurer que ces journaux gardent une taille raisonnable.

On crée un fichier de conf pour nos journaux :

vim /etc/logrotate.d/save_www

Avec le contenu suivant :

/var/log/save_www.log {
monthly
missingok
rotate 6
}

On recharge la configuration du démon logrotate :

logrotate -f /etc/logrotate.conf

Script de sauvegarde des bases de données

Le script save_mysql.sh

Ce script ressemble à son copain, il fait un dump par base et fait une rotation des dumps afin de garder N jours d’historique.

On crée le fichier :

vim /root/scripts/save_mysql.sh

Copiez collez le script suivant :

#!/bin/bash

# Parametres dossiers
save_root="/root/save/mysql"
script_root="/root/scripts"
# Parametres fichiers
mysql_list="$script_root/save_mysql.list"
save_error="/root/script.error"
save_log="/var/log/save_mysql.log"
# Compte dump mysql
mysql_user="root"
mysql_pass="<password>"

# Dump base par base
for mysql_site in `cat "$mysql_list"`
do

        # Dump de la base
        debug=`mysqldump -u $mysql_user --password=$mysql_pass --add-drop-table $mysql_site > "$save_root/$mysql_site.sql.tmp"`

        # Check reussite commande MYSQLDUMP
        if [[ $? -ge "1" ]]
        then
                # Commande echouee
                echo "`date +%d/%m/%y-%H:%M:%S` : Erreur sauvegarde de la base $mysql_site" >> "$save_log"
                rm "$save_root/$mysql_site.sql.tmp"
                echo "$debug" > $save_error
                exit
        fi

        # Rotation des archives
        for (( i=8; i>0; i-- ))
        do
                # Le dump precedent
                j=`expr $i - 1`
                if [[ $j -ge "1" ]]
                then
                        # Check dump existe
                        if [[ -e "$save_root/$mysql_site.sql.$j" ]]
                        then
                                # Le premier dump ne s'appelle pas .sql.0
                                debug=`mv "$save_root/$mysql_site.sql.$j" "$save_root/$mysql_site.sql.$i"`
                                # Check reussite commande MV
                                if [[ $? -ge "1" ]]
                                then
                                        # Commande echouee
                                        echo "`date +%d/%m/%y-%H:%M:%S` : Erreur mv $mysql_site.sql.$j vers $mysql_site.sql.$i" >> "$save_log"
                                        echo "$debug" > $save_error
                                        exit
                                fi
                        fi
                else
                        # Check dump existe
                        if [[ -e "$save_root/$mysql_site.sql" ]]
                        then
                                debug=`mv "$save_root/$mysql_site.sql" "$save_root/$mysql_site.sql.$i"`
                                # Check reussite commande MV
                                if [[ $? -ge "1" ]]
                                then
                                        # Commande echouee
                                        echo "`date +%d/%m/%y-%H:%M:%S` : Erreur mv $mysql_site.sql vers $mysql_site.sql.$i" >> "$save_log"
                                        echo "$debug" > $save_error
                                        exit
                                fi
                        fi
                fi
        done

        # Nouveau dump
        debug=`mv "$save_root/$mysql_site.sql.tmp" "$save_root/$mysql_site.sql"`
        # Check reussite commande MV
        if [[ $? -ge "1" ]]
        then
              # Commande echouee
              echo "`date +%d/%m/%y-%H:%M:%S` : Erreur mv $mysql_site.sql.tmp vers $mysql_site.sql" >> "$save_log"
              echo "$debug" > $save_error
              exit
        fi

        # Taille nouveau dump
        size_mysql=`du -hs "$save_root/$mysql_site.sql" | awk '{ print $1 }'`

        # Log le dump
        echo "`date +%d/%m/%y-%H:%M:%S` : Sauvegarde de la base $mysql_site [$size_mysql]" >> "$save_log"

done

# Permissions sur dumps
cd $save_root
chmod 400 *

Pensez à changer le mot de passe root de la base au début du script. Il est conseillé néanmoins de créer un utilisateur dédié à cette tache.

Pensez à ajouter les droits d’exécution :

chmod 754 /root/scripts/save_mysql.sh

Le fichier save_mysql.list

Dans ce fichier, on liste les bases à sauvegarder. Un nom de base par ligne, avec un retour chariot pour séparer.

On crée le fichier :

vim /root/scripts/save_mysql.list

Exemple de fichier :

mysql
test
blog

Mise en place du cron

On édite la crontab :

crontab -e

On ajoute cette ligne :

# Sauvegarde MySQL
30 0 * * * bash /root/scripts/save_mysql.sh > /dev/null

Rotation des logs

Le script écrit un événement dans un journal à chaque sauvegarde. On va utiliser logrotate.d pour s’assurer que ces journaux gardent une taille raisonnable.

On crée un fichier de conf pour nos journaux :

vim /etc/logrotate.d/save_mysql

Avec le contenu suivant :

/var/log/save_mysql.log {
monthly
missingok
rotate 6
}

On recharge la configuration du démon logrotate :

logrotate -f /etc/logrotate.conf

Conclusion

Deux scripts bash, deux cron et on a une sauvegarde facile a restaurer de ses sites oueb. Il ne faut pas oublier de sauvegarder ensuite le dossier /root/save sur un support externe. Ces sauvegardes servent principalement à remonter un site web qui a été attaqué ou cassé par une modification. En cas de crash serveur, il est souvent plus simple de restaurer la machine entière.

Pour restaurer un site, lancez les commandes suivantes :

cp -p /root/save/www/<site_web>.tar.gz.<chiffre> /tmp/
cp -p /root/save/mysql/<site_web>.sql.<chiffre> /tmp/
tar zxvf /root/save/www/<site_web>.tar.gz.<chiffre>
cd /var/www
rm -rf <site_web>
mv /tmp/<site_web> .
cd /tmp/
mysql -u root -p <site_web> < <site_web>.sql.<chiffre>
rm /tmp/<site_web>.tar.gz.<chiffre>
rm /tmp/<site_web>.sql.<chiffre>

Références

Image Tuxs Siamois : http://tux.crystalxp.net/fr.id.2091-masterlud-tuxs-siamois.html

ArticleGeekapachebackupbashhttpdmysqlmysqldumpsauvegardewww
Le contenu de ce site est sous licence Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)

Gamb

DIY

OwnCloud : L'outil collaboratif ultime ?

Installation d'un Service Provider SimpleSamlPhp