Tutoriel Backup-Manager
- "Tu as fais ta sauvegarde ? "
- "Naan, je verrai ça demain... "
Si vous vous reconnaissez au dessus, le tuto est fait pour vous !
Backup-Manager est un outil qui va vous permettre d'automatiser vos sauvegardes de manière simple avec une grande souplesse de configuration.
Je vais vous montrer ce que j'ai monté avec, donc il ne s'agit pas de suivre un tuto au pied de la lettre mais d'avoir des pistes pour adapter la chose en fonction de vos besoins.
Dans l'exemple à suivre, voilà ce que je voulais obtenir:
- un dossier sur le serveur pour sauvegarder en ftp des trucs depuis la maison.
- sauvegarder 4 db mysql, une sur le serveur de backup et 3 autres qui sont sur un autre serveur.
- faire une copie de mes sauvegardes sur l'espace FTP de backup fourni par dedibox.
- avoir un récap' des sauvegarde par mail.
Ça va permettre de voir un peu les possibilités du bousin...
1) On va commencer par créer un utilisateur et un espace de stockage en /home qui servira à regrouper tout ce qu'on veut mettre à l'abri (copie local, envoi ftp, rsync...) :
useradd backup-manager
passwd backup-manager
et le dossier qui regroupera nos sauvegardes (locale & distante)
mkdir /home/backup
chown -R backup-manager:backup-manager /home/backup
chmod -R 770 /home/backup
J'ai fais le choix de ne pas choorter l'utilisateur, donc pour conserver l'accès FTP avec VsFTPd:
nano /etc/vsftpd.chroot_list
et on ajoute le nom d'user:
backup-manager + reload:
/etc/init.d/vsftpd reload
et je lui ouvre la porte en console (j'en ai pas besoin pour l'instant mais ça peut venir):
nano /etc/ssh/sshd_config
AllowUsers backup-manager
/etc/init.d/ssh restart
2) On passe à l'installation, rien de méchant:
apt-get install backup-manager
Et au choses sérieuses avec la partie configuration:
nano /etc/backup-manager.conf
Je vais faire l'impasse sur tout ce qui reste par défaut sauf si il y a une bonne raison d'en parler 😉
export BM_REPOSITORY_ROOT="/var/archives"
J'ai gardé le dossier par défaut pour stocker les sauvegardes mais dans le cadre d'une installation "seedbox" il y a une risque de manque de place donc il faudra modifier ça en :
export BM_REPOSITORY_ROOT="/home/archives"
Il m'a créé le dossier tout seul, ça devrait être la même chose pour /home/archives, en cas d'erreur au premier test, go "mkdir".
export BM_ARCHIVE_TTL="7"
Le nombre de jours pour la rotation des sauvegardes (5 par défaut), une semaine me parait pas mal.
export BM_REPOSITORY_RECURSIVEPURGE="true"
bien faire attention à ce que le paramètre soit sur "
true" pour que backup-manager efface les sauvegarde obsolète. D'après Google, c'est un grand classique le dd plein à craqué à cause de ça donc...
export BM_ARCHIVE_PURGEDUPS="false"
J'ai passé le paramètre sur
false, cette histoire de lien symbolique pour gagné de la place m'a pas plu. Si un jour j'ai besoin de restaurer, j'aurais surement d'autre soucis que de comprendre comment le truc fonctionne donc je veux avoir des "vrais" sauvegardes tous les jours, la place n'est pas un soucis.
# The backup method to use.
# Available methods are:
# - tarball
# - tarball-incremental
# - mysql
# - pgsql
# - svn
# - pipe
# - none
# If you don't want to use any backup method (you don't want to
# build archives) then choose "none"
Là on va choisir les méthodes de sauvegarde, pour les mêmes raisons qu'au dessus, je ne veux pas d'incremental.
donc pour mon dossier backup et mes db séparé par un espace :
export BM_ARCHIVE_METHOD="tarball mysql"
la ligne du dessous mérite quelque explication
Elle permet de choisir de compresser les archives ou non et de choisir son mode de compression.
En archives, on a du choix !
tar, tar.gz, tar.bz2, tar.lz, dar, zip
Dans mon cas, je ne compresse pas car tout arrivera déjà en format gzip (tar.gz) dans le dossier depuis l'extérieur (maison et autres serveurs
Donc à vous de voir en fonction de l'utilisation, un ="tar.gz" peut être un meilleur choix dans le cadre d'une utilisation "normale"
export BM_TARBALL_FILETYPE="tar"
export BM_TARBALL_DIRECTORIES="/home/backup"
On défini notre dossier à sauvegarder /home/backup créé plus haut (j'expliquerai à la fin comment faire pour sauvegarder plusieurs dossiers).
3) Sauvegarde MySQL
export BM_MYSQL_DATABASES="mondedie"
Si plusieurs db on peut mettre juste "
__ALL__" pour toute les regrouper dans une seule archive, ou séparer les noms par un espace et avec une archives par db "
mondedie truc machin" (je préfère cette soluce)
La suite est assez simple:
export BM_MYSQL_SAFEDUMPS="true"
export BM_MYSQL_ADMINLOGIN="root"
export BM_MYSQL_ADMINPASS="monpass"
Sauf bonne raison, on laisse "
localhost" et le port "
3306" et on choisit gzip pour la compression:
export BM_MYSQL_FILETYPE="gzip"
4) Réplication des archives
Pour pouvoir envoyer une copie de mes sauvegardes sur le ftp de backup dedibox
export BM_UPLOAD_METHOD="ftp"
export BM_UPLOAD_HOSTS="dedibackup-dc2.online.net"
Pour la ligne en dessous, en fonction de vos choix (expliqué plus haut) il faudra peut-être la modifier en "
/home/archives/uploads"
export BM_UPLOAD_DESTINATION="/var/archives/uploads"
5) # The FTP method
On remplit les info users fourni par dédibox ou le ftp distant que vous utilisez:
export BM_UPLOAD_FTP_USER="mon-identifiant"
export BM_UPLOAD_FTP_PASSWORD="mon-pass"
export BM_UPLOAD_FTP_HOSTS="dedibackup-dc2.online.net"
j'autorise Backup-Manager à effacer les archives obsolètes
export BM_UPLOAD_FTP_PURGE="true"
toujours mes 7 jours pour la rotation:
export BM_UPLOAD_FTP_TTL="7"
On définit le chemin distant pour déposer les archives (la racine du ftp dans mon cas) :
export BM_UPLOAD_FTP_DESTINATION="/"
6) # Section "BURNING"
On désactive la sauvegarde auto sur cd-rom ( rigolez pas, au premier test ma console s'est figé en attendant que je mette le disque

)
export BM_BURNING_METHOD="none"
7) # Advanced settings
La section va nous permettre de lancer des script avant et après sauvegarde.
Rien pour l'instant pour l'avant:
export BM_PRE_BACKUP_COMMAND=""
et on renseigne le script d'après qui va lancer un contrôle sur le bon déroulement du backup:
export BM_POST_BACKUP_COMMAND="/usr/share/scripts-perso/backup-manager-post.php"
ce script contrôlera la bonne réception sur le ftp de dedibox et l'intégrité des archives en comparant le MD5
A noter que j'utilise le ftp pour la réplication mais le choix des protocoles est assez large:
scp ssh-gpg ftp rsync s3
On a fini pour la conf ! (qui a dit ouf ? ) Le fichier est extrêmement bien commenté et avec la coloration de Nano on si retrouve très bien.
Programmer les sauvegardes
Pour lancer Backup-Manager toute les nuits, on va créer un script:
nano /usr/share/scripts-perso/backup-manager.sh
(attention au chemin, "script-perso" c'est chez moi les gars, vous adaptez comme vous voulez !)
et on colle:
#!/bin/sh
test -x /usr/sbin/backup-manager || exit 0
/usr/sbin/backup-manager
On le rend exécutable:
chmod +x /usr/share/scripts-perso/backup-manager.sh
et on ajoute dans crontab
crontab -e
35 1 * * * sh /usr/share/scripts-perso/backup-manager.sh > /dev/null 2>&1
pour le lancer à 1h35 du matin par exemple.
Recevoir un récapitulatif par mail
Un peu plus haut dans le fichier de conf, on a déclarer un script de post-installation...
On commence par faire une modif dans /etc/php5/cli/php.ini (attention, c'est pas le meme fichier que dans le tuto rutorrent

)
nano /etc/php5/cli/php.ini
on cherche la ligne
;date.timezone =
qu'on replace par (sans oublier de retirer le "
; ":
date.timezone = Europe/Paris
On va créer le script maintenant (même mise en garde pour le chemin du fichier que plus haut) :
nano /usr/share/scripts-perso/backup-manager-post.php
et on va coller ça, il faudra modifier les infos en début de fichier pour vos mails ect... dans "configuration" :
#!/usr/bin/php
<?php
/**
* backup-manager post script :
* - permet de vérifier l'intégrité des fichiers uploadés sur le serveur de sauvegarde
* (comparaison des chaines md5)
* - envoie d'un mail récapitulatif contenant la liste des fichiers et la taille totale utilisée
*
* @references script inspiré de Alsacréation : http://www.alsacreations.com/tuto/lire/618-Sauvegarde-backup-manager.html et @Franek <franek at chicour dot net>
* @author alexandre.laidin
*/
/**
* Configuration
*/
# email de l'expediteur
$email_from = 'root@votre-domaine-ou-nom-serveur';
# email des destinataires
$email_dest = array('votre@email.com');
# répertoire local de stockage des fichiers de sauvegarde
$archives_dir = '/var/archives';
# adresse du serveur FTP
$ftp_server = 'dedibackup-dc2.online.net';
# identifiant du serveur FTP
$ftp_user_name = 'votre-identifiant';
# mot de passe du serveur FTP
$ftp_user_pass = 'votre-mot-de-passe';
$ftp_directory = '/';
/**
* Ne pas modifier - ci-dessous
*/
/**
*
* Envoi d'un mail
*
* @param array $email_dest
* @param string $subject
* @param string $content
*/
function sendMail($email_dest, $subject, $content, $headers)
{
foreach($email_dest as $dest)
{
mail($dest, $subject, $content, $headers);
}
}
/**
* Récupère la liste des fichiers présents en local pour une date donnée
* @param $archives_dir string répertoire de stockage des fichiers
* @param $filtre_date string date à filtrer (format YYYYMMDD)
* @return array
*/
function getLocalFiles($archives_dir, $filtre_date)
{
clearstatcache();
$files = array();
foreach (new DirectoryIterator($archives_dir) as $file_info)
{
if($file_info->isDot() || !preg_match('/'.date('Ymd').'/',$file_info->getFileName()))
{
continue;
}
$file['name'] = $file_info->getFilename();
// on utilise cette commande car filesize ne gère pas les fichiers de plus de 2Go.
$file['size'] = exec("stat -c %s '".$file_info->getPathname()."'");
$files[] = $file;
}
sort($files);
return $files;
}
/**
*
* Compare le hachage md5 des fichiers locaux avec les fichiers envoyés
* sur le serveur FTP
* Si le hachage est identique, renvoie true.
* Sinon, renvoie false
*
* @param string $md5_file
* @param string $ftp_server
* @param string $ftp_user_name
* @param string $ftp_user_pass
* @param string $filtre_date
* @return bool
*/
function verifMd5Ftp($md5_file, $ftp_server, $ftp_user_name, $ftp_user_pass, $ftp_directory)
{
$handle = fopen($md5_file, "r");
if ($handle !== false)
{
while (!feof($handle))
{
$buffer = fgets($handle, 4096);
if (!empty($buffer)){
list($md5, $filename) = explode(" ", $buffer);
// pour supprimer /n
$filename = trim($filename);
if (!empty($filename))
{
if ($md5 !== getMd5OverFtp($filename, $ftp_server, $ftp_user_name, $ftp_user_pass, $ftp_directory))
{
fclose($handle);
return false;
}
}
}
}
fclose($handle);
}
else
{
return false;
}
return true;
}
/**
* * Renvoie le hachage md5 d'un fichier présent sur le serveur FTP de sauvegarde
*
* @param string $file fichier dont le md5 doit être calculé
* @param string $ftp_server adresse du serveur FTP de sauvegarde
* @param string $ftp_user_name identifiant de connexion du serveur FTP
* @param string $ftp_user_pass mot de passe de connexion du serveur FTP
* @return string
*/
function getMd5OverFtp($file, $ftp_server, $ftp_user_name, $ftp_user_pass, $ftp_directory)
{
$connect_string = 'ftp://';
$connect_string .= $ftp_user_name;
if (!empty($ftp_user_pass))
{
$connect_string .= ':'.$ftp_user_pass;
}
$connect_string .= '@'.$ftp_server;
$connect_string .= $ftp_directory;
$connect_string .= '/'.$file;
return md5_file($connect_string);
}
/**
* Renvoie la taille du fichier en un format compréhensif
*
* source : http://fr.php.net/manual/en/function.filesize.php (nak5ive at DONT-SPAM-ME dot gmail dot com)
*
* @param int $bytes
* @param int $precision
* @return string
*/
function formatBytes($bytes, $precision = 2)
{
$units = array('B', 'KB', 'MB', 'GB', 'TB');
$bytes = max($bytes, 0);
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
$pow = min($pow, count($units) - 1);
$bytes /= pow(1024, $pow);
return round($bytes, $precision) . ' ' . $units[$pow];
}
/**
* début du script
*/
$date = date('Ymd');
$host = trim(file_get_contents('/etc/hostname'));
# fichier contenant les chaines md5 de tous les fichiers sauvegardés
$md5_file = $archives_dir.'/'.$host.'-'.$date.'.md5';
$check_md5_ftp = false;
$output = "";
$message_html = "<html><head></head>";
$message_html .= "<style type='text/css'> table{border:solid 1px #777777; border-collapse:collapse; font-family:arial;";
$message_html .= "body{font-family:Arial, Helvetica, sans-serif; font-size:13px;}";
$message_html .= ".info, .success, .warning, .error, .validation {border: 1px solid;margin: 10px 0px;padding:15px 10px 15px 50px;";
$message_html .= ".info {color: #00529B;background-color: #BDE5F8;}";
$message_html .= ".success {color: #4F8A10;background-color: #DFF2BF;}";
$message_html .= ".warning {color: #9F6000;background-color: #FEEFB3;}";
$message_html .= ".error {color: #D8000C;background-color: #FFBABA;}";
$message_html .= "</style>";
$message_html.= "<body>";
clearstatcache();
$local_files = getLocalFiles($archives_dir, $date);
$subject = '['.$host.']';
if(empty($local_files))
{
$message_html .= "<div class='error'>Fichiers non présents en local</div>";
$subject .= ' - Backup - LOCAL KO';
}
else
{
$subject .= ' - Backup - LOCAL OK';
$message_html .= "<div class='info'>Sauvegarde Local effective</div>";
$message_html .= "<table cellspacing='0' cellpadding='3px' rules='rows'>";
$message_html .= "<caption>Détail de la sauvegarde</caption>";
$message_html .= "<thead><tr class='ligne'><th class='colti'>Fichier</th><th>Taille</th></tr></thead>";
$total_size = 0;
// affichage de la liste des fichiers avec leur taille et un total global
foreach($local_files as $file)
{
$message_html .= "<tr><td class='colti'>".$file['name']."</td><td>".formatBytes($file['size'])."</td></tr>";
$total_size += $file['size'];
}
$message_html .= "<tfoot><tr><td>Total :</td><td>".formatBytes($total_size)."</td></tr></tfoot></table>";
$message_html .= "</br></br>";
// lance la vérification md5 des fichiers uploadés sur le serveur FTP
$check_md5_ftp = verifMd5Ftp($md5_file, $ftp_server, $ftp_user_name, $ftp_user_pass, $ftp_directory);
if ($check_md5_ftp === false)
{
$message_html .= "<div class='warning'>Problème d'intégrité des fichiers sur serveur FTP</div>";
$subject .= ' - FTP KO';
}
else
{
$message_html .= "<div class='info'>Intégrité contrôlée des fichiers sur serveur FTP</div>";
$subject .= ' - FTP OK';
}
}
$message_html.= "</body></html>";
//$headers = "From: root <>\r\n";
//$headers = "From: root@nagasaki.ratbox.nl\n";
$headers = "From: $email_from\n";
$headers .= "MIME-Version: 1.0\r\n";
$headers .= "Content-Type: text/html; charset=utf8\r\n";
sendMail($email_dest, $subject, $message_html, $headers);
?>
On le rend exécutable:
chmod +x /usr/share/scripts-perso/backup-manager-post.php
Pour tester, ou pour lancer une sauvegarde manuellement, il suffit de taper en console:
backup-manager
A ce niveau du tuto, on peut se connecter de l’extérieur en ftp (avec l'user backup-manager créé au début) pour mettre des choses à sauvegarder dans /home/backup et notre db mysql local sera sauvegardé.
Toutes les nuits, on aura une sauvegarde dans /var/archives et une réplication sur le ftp dédibox
Un petit mot sur la place. Faites quand même attention au poids de vos sauvegardes car ça grimpe relativement vite.
Avec 7 jours de backup, on a donc 8 versions de chaque fichiers sur le serveur.
- 1 dans /home/backup et les 7 autres dans /var/archives (pour ça que je parle d'un
/home/archives au début !)
- Pareil sur le ftp-dedibox => 7 versions, donc avec 100 Go d'espace, éviter de trop dépasser les 10 Go pour en garder sous le coude sinon vous aller vite être court
A suivre :
- Script de pré-backup pour sauvegarder des dossiers particuliers et les regrouper en /home/backup, j'ai trouvé un beta-testeur de qualité !

- Explication sur la possibilité d'avoir plusieurs fichiers de conf, pour par exemple lancer un backup de ses sites en /var/www une fois par semaine. ( bon c’est pas un très bon exemple mais vous voyez l'idée

)
Ex.