Script de sauvegarde serveur Debian + IspConfig3

Salut,
J’ai fait (disons plutôt que j’ai compilé des morceaux de scripts, piqués à droite et à gauche) un petit script destiné à sauvegarder les fichiers importants de mon serveur dédié (Squeeze + IspConfig3)
Je vous le propose ici (et non pas dans le fil: pour les scripts c’est ici) afin de l’améliorer si vous y voyez des aberrations…

Le script (lancé par une tâche cron) sauvegarde journalièrement les sites Webs, les bases sql, les emails, l’intégralité du dossier /etc et les fichiers de configuration de IspConfig3 - Basesql et dossier)
Puis ces fichiers sont envoyés sur le FTP de OVH (Ce ftp “interne” n’est accessible que depuis le dédié, c’est donc assez sécurisé)

Deux jours de sauvegarde sur le serveur, idem sur le ftp.

[code]#!/bin/bash

Sauvegarde quotidienne: Sites, Bases Mysql, Emails, fichiers de configuration.

###################################################################### Variables
HOST=“localhost”

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Chemins

CHEMIN="/usr/local/scripts/“
DEST=”/var/backup/“
DESTSITE=”/var/backup/sites/“
DESTSQL=”/var/backup/mysql/“
DESTISP=”/var/backup/isp/"

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Connexion sql et root

DB="dbispconfig"
USER="root"
PASS=‘motdepasseroot’

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Dates

DATE="$(date +%F)“
DATE2=”$(date -d ‘2 days ago’ +%F)"

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Chemins exécutables

MYSQL="$(which mysql)“
MYSQLDUMP=”$(which mysqldump)“
CHOWN=”$(which chown)“
CHMOD=”$(which chmod)“
GZIP=”$(which gzip)"

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Divers Mysql

DBS="" # liste des bases
NODB=“information_schema” # databases à ne pas sauvegarder

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> FTP

FTP_HOST="nomdevotreftp"
FTP_USER="utilisateur"
FTP_PASS=“motdepasseftp”

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Divers

TEMP="brut"
MAIL=“admin@mondomaine.tld” # destinataire du mail contenant les logs

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Logs

LOGS="/var/backup/logs" # Répertoire pour les logs des backups
[ ! -d $LOGS ] && mkdir -p $LOGS # Préparation du répertoire pour les logs
LOGNAME=${DATE}"-backuplog.txt"
LOGNAME2=${DATE2}"-backuplog.txt"
LOGFILE=${LOGS}"/"${LOGNAME}
LOGFILE2=${LOGS}"/"${LOGNAME2}

function log_msg () {
echo “$(date +%X): $@” >> “$LOGFILE”
}

log_msg "************************************************************"
log_msg "date +%X: Début de la sauvegarde"
log_msg “************************************************************”[/code]

[code]###################################################################### BACKUP SITES
[ ! -d $DESTSITES ] && mkdir -p $DESTSITES

Récupération infos clients et sites

cd "$CHEMIN"
echo “select system_user,system_group from web_domain” | mysql -u $USER -p$PASS -D $DB > $TEMP
tail -n +2 “$TEMP” > liste
rm “$CHEMIN/$TEMP”

Début boucle liste

while read ligne
do
set $(echo $ligne)
# Variables boucle
SITE=$(eval echo $1)
CLIENT=$(eval echo $2)

# Sauvegarde Sites
cd /var/backup/sites/
tar zcfP "$SITE"-"$DATE".tar.gz /var/www/clients/"$CLIENT/$SITE"
# Effacer les sauvegardes de plus de 2 jours
TARGZOLD="$DESTSITES$SITE-$DATE2".tar.gz
[ -f $TARGZOLD ] && rm -f $TARGZOLD || :

log_msg "`date +%X`: $CLIENT Site $SITE sauvegarde terminée"

done < liste

rm “$CHEMIN/liste”[/code]

[code]###################################################################### BACKUP SQL
[ ! -d $DESTSQL ] && mkdir -p $DESTSQL

Seul Root accède aux backups!

$CHOWN 0.0 -R $DEST
$CHMOD 0600 $DEST

OLDOFS=$OFS
OLDIFS=$IFS
DBS=( $($MYSQL -u $USER -h $HOST -p$PASS -Bse ‘show databases’) )
OFS=$OLDOFS
IFS=$OLFIFS

for db in "${DBS[@]}"
do
skipdb=-1
if [ “$NODB” != “” ];
then
for i in $NODB
do
[ “$db” == “$i” ] && skipdb=1 || :
done
fi

if [ "$skipdb" == "-1" ] ; then
    SQLGZ="$DESTSQL$db.$DATE.gz"
    $MYSQLDUMP -u $USER -h $HOST -p$PASS $db | $GZIP -9 > $SQLGZ
log_msg "`date +%X`: $SQLGZ sauvegarde terminée"

    # Effacer les sauvegardes de 2 jours
    SQLGZOLD="$db.$DATE2.gz"
    if test -f "$DESTSQL$SQLGZOLD"; then
    echo 'suppression des backups 2 jours'
    rm -f "$DESTSQL$SQLGZOLD"
    fi

fi

done[/code]

[code]###################################################################### BACKUP /etc /var/vmail IscpConfig
[ ! -d $DESTISP ] && mkdir -p $DESTISP
cd $DESTISP
tar -pczf etc-$DATE.tar.gz /etc
log_msg “date +%X: etc-$DATE.tar.gz sauvegarde terminée”

rm etc-$DATE2.tar.gz

service postfix stop
tar -pczf vmail-$DATE.tar.gz /var/vmail
service postfix start
log_msg "date +%X: vmail-$DATE.tar.gz sauvegarde terminée"
rm vmail-$DATE2.tar.gz /var/vmail

mysqldump -u root -p"$PASS" dbispconfig > “$DESTISP”/dbispconfig-$DATE.sql; gzip -f “$DESTISP”/dbispconfig-$DATE.sql
log_msg "date +%X: dbispconfig-$DATE.sql.gz sauvegarde terminée"
rm dbispconfig-$DATE2.sql.gz

tar -pczf ispconfig_software-$DATE.tar.gz /usr/local/ispconfig
log_msg "date +%X: ispconfig_software-$DATE.tar.gz sauvegarde terminée"
rm ispconfig_software-$DATE2.tar.gz[/code]

[code]###################################################################### ENVOI SUR FTP OVH
log_msg "*********************************************************
log_msg "date +%X Début des transferts FTP”
################################################################ Préparation FTP (jour vers jour-1)
ftp -in <> $LOGFILE
open ${FTP_HOST}
user ${FTP_USER} ${FTP_PASS}
bin
verbose
mdelete jour-1/isp/

mdelete jour-1/mysql/

mdelete jour-1/sites/

rmdir jour-1/isp
rmdir jour-1/mysql
rmdir jour-1/sites
rmdir jour-1
rename /jour /jour-1
mkdir /jour
mkdir /jour/isp
mkdir /jour/mysql
mkdir /jour/sites
bye
EOF
################################################################ Envoi bases sql sur ftp
cd $DESTSQL
shopt -s nullglob
FICHIERS=( *${DATE}.gz )

(( ${#FICHIERS[@]} > 0 )) && ftp -in <> $LOGFILE
open ${FTP_HOST}
user ${FTP_USER} ${FTP_PASS}
bin
verbose
cd /jour/mysql
$(printf “put %s\n” “${FICHIERS[@]}”)
bye
EOF
################################################################ Envoi sites sur ftp
cd $DESTSITE
shopt -s nullglob
FICHIERS=( *${DATE}.tar.gz )

(( ${#FICHIERS[@]} > 0 )) && ftp -in <> $LOGFILE
open ${FTP_HOST}
user ${FTP_USER} ${FTP_PASS}
bin
verbose
cd /jour/sites
$(printf “put %s\n” “${FICHIERS[@]}”)
bye
EOF
################################################################## Envoi /etc /var/vmail dbispconfig et ispconfig sur ftp
cd $DESTISP
shopt -s nullglob
FICHIERS=( *${DATE}.tar.gz )

(( ${#FICHIERS[@]} > 0 )) && ftp -in <> $LOGFILE
open ${FTP_HOST}
user ${FTP_USER} ${FTP_PASS}
bin
verbose
cd /jour/isp
$(printf “put %s\n” “${FICHIERS[@]}”)
bye
EOF

cd $DESTISP
shopt -s nullglob
FICHIERS=( *${DATE}.sql.gz )

(( ${#FICHIERS[@]} > 0 )) && ftp -in <> $LOGFILE
open ${FTP_HOST}
user ${FTP_USER} ${FTP_PASS}
bin
verbose
cd /jour/isp
$(printf “put %s\n” “${FICHIERS[@]}”)
bye
EOF
################################################################## Fin de la sauvegarde!
log_msg "************************************************************"
log_msg "date +%X Fin du script de sauvegarde "
cat $LOGFILE | mail -s “Résultat Sauvegarde du $DATE” $MAIL -r root
rm $LOGFILE2 # Nettoyage des logs
exit[/code]

Merci pour vos commentaires et idées pour améliorer.

Sur cette partie :

[code]# Liste des bases à sauver
DBS="$($MYSQL -u $USER -h $HOST -p$PASS -Bse ‘show databases’)"

for db in $DBS
do
# pleins de traitements
done[/code]
Cette commande :

Te sort des chose sous quelle forme ? Car la si l’une des base a un espace dans son nom (je ne sais pas si c’est possible sous MySQL) alors du va te faire planter.
Ici je vois que c’est un nom par ligne : java2s.com/Code/SQL/Database … nmysql.htm (mais c’est dans le shell de mysql).

Si c’est le cas tu as plusieurs solutions. Utiliser read, avec un truc un peu comme ça :

for db in $DBS
while read db
do
    # pleins de traitements
done <$($MYSQL -u $USER -h $HOST -p$PASS -Bse 'show databases')

Changer le IFS :

OLDIFS="$IFS" IFS="\n" for db in $DBS do # pleins de traitements done IFS="$OLDIFS"

Voir en utilisant un tableau :

[code]
OLDIFS="$IFS"
IFS="\n"
DBS=( $($MYSQL -u $USER -h $HOST -p$PASS -Bse ‘show databases’) )
IFS="$OLDIFS"

for db in $DBS
do
# pleins de traitements
done[/code]

Mais c’est à tester.

Oui, je n’avais pas pensé à ça. Il me sort une liste (sur une seule ligne). Mes bases n’ont pas d’espace dans le nom, mais c’est une éventualité à prendre en compte…
Je regarde comment mettre ta solution dans le script.

Merci.

C’était ce que je craignais.

Tu peut tenter (sans grand espoir de ma part) avec ça :

export OFS="\n"
$MYSQL -u $USER -h $HOST -p$PASS -Bse 'show databases'

Voir ce qu’il te sort.

Je vois que tu as quelques lignes de ce type là :

Tu pourrais les remplacer par un appel à une fonction :

function log_msg () {
    echo "$(date +%X): $@" >> "$LOGFILE"
}

# plus loin dans le code

log_msg "$CLIENT Site $SITE sauvegarde terminée"

Les avantages :
[ul]
[li]si tu veut modifier ton format de log tu le fait à un seul endroit[/li]
[li]si tu veut apporter une autre correction (comme encadrer la variable $LOGFILE par des "), tu le fait à un seul endroit[/li]
[li]je pense que log_msg "$CLIENT Site $SITE sauvegarde terminée" est plus lisible que echo "`date +%X`: $CLIENT Site $SITE sauvegarde terminée" >> $LOGFILE[/li][/ul]

Je ne comprends pas l'intérêt de la fin :
[code]|| :[/code]
?

C'est pour que la commande soit toujours vrai ? Je ne vois pas de set -e

Je ne comprends pas l’intérêt de la fin :

?

C’est pour que la commande soit toujours vrai ? Je ne vois pas de set -e

Salut,
C’est gentil d’avoir pris le temps de passer dans le code.
Pour les logs, c’est noté, je rectifierais, c’est plus propre.

Pour ça: || : J’enlèverais aussi. J’ai surement trainé ça d’un autre script, sans songer à l’enlever.

Pour la variable DBS… J’ai plus de mal.

export OFS="\n" $MYSQL -u $USER -h $HOST -p$PASS -Bse 'show databases'Me sort bien une liste, une sortie par ligne.

Par contre si j’essaye ça:export OFS="\n" DBS="$($MYSQL -u $USER -h $HOST -p$PASS -Bse 'show databases')" echo $DBS

Il me ressort une liste sur une seule ligne.
Quel est la fonction de “OFS” ?

Merci

OFS pour Output Field Separator, permet de redéfinir le caractère séparateur entre les champ que mysql te sort (mais ça marche avec pleins de truc). Ça permet de distinguer les éventuels espace des noms de base des espaces séparateurs.

Tu devrais pouvoir faire ça :

OLDOFS=$OFS
OLDIFS=$IFS
DBS=( $($MYSQL -u $USER -h $HOST -p$PASS -Bse 'show databases') )
OFS=$OLDOFS
IFS=$OLFIFS

Re,
J’ai essayé ceci:

OLDOFS=$OFS OLDIFS=$IFS DBS=( $($MYSQL -u $USER -h $HOST -p$PASS -Bse 'show databases') ) for db in $DBS do echo $DBS done OFS=$OLDOFS IFS=$OLFIFS

Il ne me sort que le premier nom de la liste.
Excuse moi pour mon misérable niveau…

Repositionne les variables avant la boucle pour voir. :slightly_smiling:

Il n’y a pas de mal comme tout le monde on avance à tâtons.

Il a fallut que je change ceci:DBS=( $($MYSQL -u $USER -h $HOST -p$PASS -Bse 'show databases') )
Sinon ça ne me sort que le premier nom de la liste

[code]OLDOFS=$OFS
OLDIFS=$IFS
DBS="$($MYSQL -u $USER -h $HOST -p$PASS -Bse ‘show databases’)"
OFS=$OLDOFS
IFS=$OLFIFS

for db in $DBS
do
echo $DBS
done[/code]

Là j’ai bien toute ma liste, un nom par ligne!

Marche pas…

[code]OLDOFS=$OFS
OLDIFS=$IFS
DBS="$($MYSQL -u $USER -h $HOST -p$PASS -Bse ‘show databases’)"
OFS=$OLDOFS
IFS=$OLFIFS

for db in $DBS
do
skipdb=-1
if [ “$NODB” != “” ];
then
for i in $NODB
do
[ “$db” == “$i” ] && skipdb=1 || :
done
fi

if [ "$skipdb" == "-1" ] ; then
    SQLGZ="$DESTSQL$db.$DATE.gz"
    $MYSQLDUMP -u $USER -h $HOST -p$PASS $db | $GZIP -9 > $SQLGZ
log_msg "`date +%X`: $SQLGZ sauvegarde terminée"

    # Effacer les sauvegardes de 2 jours
    SQLGZOLD="$db.$DATE2.gz"
    if test -f "$DESTSQL$SQLGZOLD"; then
    echo 'suppression des backups 2 jours'
    rm -f "$DESTSQL$SQLGZOLD"
    fi

fi

done[/code]

Me sort:

./essai2.sh: line 74: /var/backup/mysql/information_schema c0articles c0baseclient c0clipperz c0cloud c0collab c0dev c0dev1 c0educa c0simple_invoices c1gallery c1hotelsIsalo c1hotelsmada c1isalo c1paste c1piwik c1pix c1relais c1spa c1wikidb c1yourls c2bidon dbispconfig mysql roundcube.2012-02-14.gz: Nom de fichier trop long mysqldump: Got error: 1102: Incorrect database name 'information_schema c0articles c0baseclient c0clipperz c0cloud c0collab c0dev c0dev1 c0educa c0simple' when selecting the database

Je suppose que le nouveau format de la variable n’est plus compatible avec la suite des opérations. Mais lesquels ? :017

[quote=“lol”][code]OLDOFS=$OFS
OLDIFS=$IFS
DBS="$($MYSQL -u $USER -h $HOST -p$PASS -Bse ‘show databases’)"
OFS=$OLDOFS
IFS=$OLFIFS

for db in $DBS
do
echo $DBS
done[/code]

Là j’ai bien toute ma liste, un nom par ligne![/quote]
Cette boucle ne fait qu’une seule itération avec une variable qui contient des \n :slightly_smiling:
Par contre je ne comprends pas ton second affichage.

Mon cerveau viens de s’allumer !
Je ne suis bête.

[code]OLDOFS=$OFS
OLDIFS=$IFS
DBS=( $($MYSQL -u $USER -h $HOST -p$PASS -Bse ‘show databases’) )
OFS=$OLDOFS
IFS=$OLFIFS

for db in "${DBS[@]}"
do
echo $DBS
done[/code]
Fonctionne.

Il reste le risque d’avoir une base qui s’appelle :

Mais je ne vois pas comment protéger unitairement chaque nom que sort mysql. Si Totor passe par là il en saura probablement plus que moi.

Magnifique, merci.

Le seul truc qui ne fonctionne pas, c’est l’exclusion (la partie skipdb).
Du coup j’ai l’erreur suivante: mysqldump: Got error: 1044: Access denied for user ‘root’@‘localhost’ to database ‘information_schema’ when using LOCK TABLES

Mais ça n’a pas d’influence sur la qualité des sauvegardes, c’est le principal! :smiley:

[code]for db in "${DBS[@]}"
do
skipdb=-1
if [ “$NODB” != “” ];
then
for i in $NODB
do
[ “$db” == “$i” ] && skipdb=1 || :
done
fi

if [ "$skipdb" == "-1" ] ; then
    SQLGZ="$DESTSQL$db.$DATE.gz"
    $MYSQLDUMP -u $USER -h $HOST -p$PASS $db | $GZIP -9 > $SQLGZ
log_msg "`date +%X`: $SQLGZ sauvegarde terminée"

    # Effacer les sauvegardes de 2 jours
    SQLGZOLD="$db.$DATE2.gz"
    if test -f "$DESTSQL$SQLGZOLD"; then
    echo 'suppression des backups 2 jours'
    rm -f "$DESTSQL$SQLGZOLD"
    fi

fi

done[/code]

EDIT: Si ça fonctionne, désolé, je me suis planté de variable… Merci.

Ha si, encore une question…

Comment intégrer la fonction log dans le code suivant:

[code]cd $DESTSQL
shopt -s nullglob
FICHIERS=( *${DATE}.gz )

(( ${#FICHIERS[@]} > 0 )) && ftp -in <> $LOGFILE
open ${FTP_HOST}
user ${FTP_USER} ${FTP_PASS}
bin
verbose
cd /jour/mysql
$(printf “put %s\n” “${FICHIERS[@]}”)
bye
EOF[/code]

Merci d’avance.

Je vois pas comment intégrer cela à la fonction de log.

Salut,

Je m’en doutais un peu, mais avec une confirmation c’est encore mieux!
Merci,
Je vais faire les corrections.

salut
euh c’est vachement compliquer votre bordel :open_mouth:

perso je fait:

#!/bin/sh
DATE="sauvegarde-"`date '+%d.%m.%Y-%H.%M.%S'`

RepAdmin="./sauvgarde"
FICHIER_INCLUDE='./include_serv.txt'
FICHIER_EXCLUDE='./exlude_serv.txt'
REPACL="$RepAdmin/$DATE"
FICHIER_STATUS="$RepAdmin/$DATE"

mkdir -p $REPACL
mkdir -p $FICHIER_STATUS
echo "\n ********************************* sauvegarde automatique en cours *********************************"
echo "Début de la sauvegarde journalière pour les droit le : $DATE" >> /var/log/sauvegarde.txt

ScanRep="/etc /usr /boot /lib /opt /sbin /root /srv /var /initrd /proc /selinux /home /bin /dev /sys /vmlinuz /initrd.img /tmp"
for TB in $ScanRep ;do
        Filesave1="$REPACL$TB.acl.$DATE"
        FULLSAVE=$TB
        echo "Demarrage : " `date` " pour $FULLSAVE"
        getfacl -R  --absolute-names $FULLSAVE  > $Filesave1
        i=$(($i+1))
done
echo "Fin de la sauvegarde des droi acl $DATE" >> /var/log/sauvegarde.txt
nice -n 20 tar -cvf "$FICHIER_STATUS.tar" -T $FICHIER_INCLUDE -X $FICHIER_EXCLUDE
echo "Opération terminée du fichier tar: " `date` >> /var/log/sauvegarde.txt
echo "\n ********************************* sauvegarde automatique terminée *********************************"
echo "sauvgarde terminée"

#pour restaurer les droit :
#setfacl --restore=$Filesave1

vous devinez la suite :
le fichier include contien les répertoires a prendre, l’autre a les exclure :slightly_smiling: liser le man :wink:

je sauvegarde les droit a par car si un changment de droit ce passe mal j’ai pas forcement envie de restaurer les fichier :wink:

pour la rotation des sauvegardes je préfère le faire a la main j’ai donc grace aux script la date inclue dasn le nom du répertoire. facile de si retrouver :slightly_smiling:

vala :006 :005

Salut,
Non, ce n’est pas si compliqué.
Mais l’ensemble des sites (et bases qui vont avec) se trouve dans une base sql.
Les fichiers à sauvegarder peuvent changer (ajout ou suppression) donc une liste “statique” n’a aucun intérêt pour moi, et il ne faut pas que je rate une site avec sa base, c’est crucial; Je promet à mes “clients” une restauration immédiate en cas de problème…

Il suffit donc d’extraire les infos de la base pour savoir quoi sauvegarder.
L’intérêt du script est de ne plus avoir à y penser, et ça fonctionne (je jette juste un oeil aux logs de temps en temps pour m’assurer que tout fonctionne…).

Il y a un complément à tout ceci, c’est un petit script qui envoie (avec ssh) mes sauvegardes sur un serveur mutualisé.
J’ai donc en tout trois jeux de sauvegardes:

  • Un sur le serveur lui-même (les deux derniers jours);
  • Un sur un serveur ftp dans le même réseau que mon serveur (les deux derniers jours);
  • Un sur un mutualisé aux US (une sauvegarde tous les 7j et une tous les 15j).

La dernière est pour me prémunir d’une éventuelle corruption du serveur détectée tardivement…

8)

[quote=“lol”]Salut,
Non, ce n’est pas si compliqué.
Mais l’ensemble des sites (et bases qui vont avec) se trouve dans une base sql.
Les fichiers à sauvegarder peuvent changer (ajout ou suppression) donc une liste “statique” n’a aucun intérêt pour moi, et il ne faut pas que je rate une site avec sa base, c’est crucial; Je promet à mes “clients” une restauration immédiate en cas de problème…

[/quote]

je vois pas comment tu peux rater ta base vu que tu sauvegarde toute la base (enfin avec ma méthode) :unamused: ce qui est plus fiable a mon avis. A moins que tu cherche a sauvegarder que ce qui change a savoir une sauvegarde incremental. dans ce cas mon script n’est pas adapter.
j’ai rater quelque chose ?