[Synology] Sauvegarde site web par FTP avec lftp


MAJ : 01/12/2012

Objectifs

  • Sauvegarder mes sites web installés chez différents hébergeurs
  • Envoyer un mail de contrôle pour m’indiquer que la sauvegarde c’est correctement déroulée ou pas

Pré requis

  • Accès telnet en root (même mot de passe que le compte Admin)
  • installation de ipkg : je vous laisse avec le petit tuto de Fredo très complet
  • installation de lftp
ipkg install lftp
  • installation de screen : permettra de lancer notre script dans une console et de récupérer la sortie du script shell.
ipkg install screen
  • création répertoire de sauvegarde

Script de sauvegarde

modifier la partie configuration du script shell en fonction de votre environnement personnel. (télécharger le script)

#!/bin/sh
######################################################################################
##### Sauvegarde fichier d'un site web distant par FTP avec lftp
######################################################################################
## Remarque sur lftp
## + Le -e de mirror efface les fichiers qui n'existent plus.
######################################################################################
## Paramètre en entrée
##     1 : -e ou rien
##		   pour effacer tous les fichiers du local qui n'existent plus sur le FTP
######################################################################################

# configuration fichier de log
ficLog=/volume1/documents/logSvgSite.txt

# configuration : ftp / user / pass
servFTP=ftp.com
userFTP=login
passFTP=password
# configuration
repFTP=/www/
repLocal=/volume1/Sauvegardes_Cobestran/
#repIgnore=""
repIgnore="-x wp-content/cache -x /wp-content/supercache"

######################################################################################
# debut shell
echo "+-- Deb Sauvegarde $(date) ---" >> ${ficLog}

# commande de copie miroir ftp vers local
/opt/bin/lftp ftp://${userFTP}:${passFTP}@${servFTP} -e "set file:charset utf8 ; set ftp:charset utf8;  mirror ${1} ${repIgnore} ${repFTP} ${repLocal} ; quit"  >> ${ficLog} 2>&1

# résultat de la commande - 0 : ok
res=$?
echo "Résultat : "${res} >> ${ficLog}
echo "--- Fin Sauvegarde $(date) ---" >> ${ficLog}

if [ ${res} -eq 0 ]
then
echo "Svg OK" | /usr/local/bin/my_sendmail -s "<sujet du mail>" -f "<addresse email expéditeur>" -m <serveur smtp> -M "txt" <addresse destinataire> ${ficLog}
else
echo "Svg avec Erreur" | /usr/local/bin/my_sendmail -s "<sujet du mail>" -f "<addresse email expéditeur>" -m <serveur smtp> -M "txt" <addresse destinataire> ${ficLog}
fi
# fin shell
echo "--- Fin ---" >> ${ficLog}
######################################################################################
exit $res

Script d’envoi de mail par smtp

Créer le fichier my_sendmail

vi /usr/local/bin/my_sendmail
#!/usr/bin/perl -w
#
#
#       my_sendmail [-m <mail server>]
#                       [-s <sujet>]
#                       [-f <from>]
#                       [-r <reply-to>]
#                       [-c <cc-dests>]
#                       [-t <type mime du contenu>]
#                       [-M <type mime des documents joints>]
#                       [-b <bcc-dests>] <dests> [<attached files>...]
#
#-

use Net::SMTP;
use MIME::Base64;
use Getopt::Std;
use File::Basename;
use Sys::Hostname;

my $progname;
( $progname = $0 ) =~ s/^.*\///;

%ctypes = (

           'tar' => 'application/x-tar',
           'man' => 'application/zip',
           'au|snd' => 'audio/basic',
           'mpg|mp3' => 'audio/mpeg',
           'mp4' => 'audio/mp4',
           'aif|aiff|aifc' => 'audio/x-aiff',
           'wav' => 'audio/x-wav',
           'gif' => 'image/gif',
           'jpg|jpeg|jpe' => 'image/jpeg',
           'png' => 'image/png',
           'tiff|tif' => 'image/tiff',
           'pbm' => 'image/x-portable-bitmap',
           'pgm' => 'image/x-portable-graymap',
           'ppm' => 'image/x-portable-pixmap',
           'zip' => 'application/x-zip',
           'gz|gzip' => 'application/x-gzip',
           'css' => 'text/css',
           'csv' => 'text/csv',
           'htm|html' => 'text/html',
           'txt|g|h|c|cc|hh|m|f90' => 'text/plain',
           'rtx' => 'text/richtext',
           'rtf' => 'text/rtf',
           'tsv' => 'text/tab-separated-value',
           'xml' => 'text/xml',
           'h264' => 'video/h264',
           'dv' => 'video/dv',
           'mpeg|mpg|mpe' => 'video/mpeg',
           'qt|mov' => 'video/quicktime',
           'avi' => 'video/msvideo',
           'pdf' => 'application/pdf',
);

#+
#       parsing des options
#-
getopts('s:f:m:c:b:vM:r:t:', \%opts) or &usage;
my $to = shift or &usage;
my $verbose = $opts{v};
my $subject = $opts{s};
my @files = ();
while ($_= shift) {
  push @files,$_;
}

my $from;

$from = $opts{f} || (($ENV{USER} || $ENV{LOGNAME} || "unknown") . "\@" . hostname);

my $smtphost = $opts{m} || "localhost"; # SMTP mail host

#+
#       séparateur multipart quasi aléatoire
#-
my $boundary = '<------------ ';
my @chrs = ('0' .. '9', 'A' .. 'Z', 'a' .. 'z');
foreach (0..16) { $boundary .= $chrs[rand (scalar @chrs)]; }
$boundary .= ' ------------>';

#+
#       initialisation dialogue smtp
#-
my $smtp = Net::SMTP->new($smtphost, Timeout => 30) or die "Net::SMTP::new: $!\n";
$smtp->mail($from);
foreach (split /,/,$to) {
  $smtp->to($_);
}
if (my $cclist = $opts{c}) {
  foreach (split /,/,$cclist) {
    $smtp->cc($_);
  }
}
if (my $cclist = $opts{b}) {
  foreach (split /,/,$cclist) {
    $smtp->bcc($_);
  }
}

#+
#       en-tetes message
#-
$smtp->data();

$smtp->datasend("From: $from\n");
$smtp->datasend("To: $to\n");
if ($opts{c}) {
  $smtp->datasend("Cc: $opts{c}\n");
}

if (exists($opts{r})) {
  $smtp->datasend("Reply-To: $opts{r}\n");
}

$smtp->datasend("Subject: $subject\n") if $subject;
$smtp->datasend("MIME-Version: 1.0\n");
$smtp->datasend("X-Mailer: $progname (MY)\n");
$smtp->datasend("Content-Type: multipart/mixed; boundary=\"$boundary\"\n");
$smtp->datasend("\n");
$smtp->datasend("This is a multipart MIME-coded message\n");
$smtp->datasend("\n");
$smtp->datasend("\n");

#+
#       partie textuelle du message (a partir de stdin)
#-
my $ctype = $opts{t} ? $opts{t} : "text/plain";
$smtp->datasend("--$boundary\n");
$smtp->datasend("Content-Type: $ctype; charset=us-ascii\n");
$smtp->datasend("Content-Transfer-Encoding: 7bit\n");
$smtp->datasend("\n");
while (<>) {
  $smtp->datasend($_);
}

#+
#       quelques lignes blanches pour aérer
#-
$smtp->datasend("\n\n\n");

#+
#       boucle sur les fichiers à attacher
#-
foreach $file (@files) {
  my $name = basename($file);
  my $extension = (fileparse($file,qr/\.[^.]*?/))[2];
  my $ct;

  #     on tente de déterminer le content type
  if ($opts{M}) {
    $ct=$opts{M};
  } else {
    $ct = "Application/octet-stream";
    foreach $type_extensions (keys %ctypes) {
      if ($extension =~ /^\.($type_extensions)$/i) {
        $ct = $ctypes{$type_extensions};
        last;
      }
    }
  }
  $smtp->datasend("--$boundary\n");
  $smtp->datasend("Content-Type: $ct; name=\"$name\"\n");
  $smtp->datasend("Content-Disposition: attachment; filename=\"$name\"\n");
  $smtp->datasend("Content-Transfer-Encoding: base64\n");
  $smtp->datasend("\n");
  open FILE,$file or die "fichier $file introuvable\n";
  while (read(FILE, $buf, 60*57)) {
    $smtp->datasend( encode_base64($buf));
  }
  print STDERR "$progname: attachement fichier $name type $ct\n" if $verbose;
}

$smtp->datasend("--$boundary--\n");
$smtp->dataend();

sub usage {
  print STDERR <<'EOD';
my_sendmail: envoi de mails avec documents attachés.

Usage:
        my_sendmail     [-m <mail server>]  
                        [-s <sujet>]
                        [-f <from>]
                        [-c <cc-dests>]
                        [-M <mime type des fichiers jointsés>]
                        [-t <mime type du corps du messages>]
                        [-v]
                        [-b <bcc-dests>] <dests> [<attached files>...] < <fichier contenant le texte du message>
EOD
  exit 1;
}

Programmer votre sauvegarde chaque jour

modifier le fichier /etc/crontab  et ajouter le lancement du script (voir article synology-planification-de-scripts)

/volume1/@optware/bin/screen -dmS "ses_svgSite" /volume1/@scripts/svgSite.sh -e

Résultats

une belle sauvegarde supervisée par mail.

/volume1/documents/logSvgSite.txt
+-- Deb Sauvegarde Fri Nov 12 17:59:44 CET 2010 ---
Total: 1119 directories, 9752 files, 0 symlinks
Removed: 2 directories, 8 files, 0 symlinks
Résultat : 0
--- Fin Sauvegarde Fri Nov 12 18:11:18 CET 2010 ---

, ,

  1. #1 by Eric on 24/08/2014 - 9 h 19 min

    Salut,
    J’essaie depuis hier soir de faire tourner en vain ton script. Dans l’ordre je trouve les pbs suivants :

    Quand je fais un copier coller de ton script dans un fichier et après configuration, il me dit erreur ligne 12, 15 …
    Cela correspond à toutes les lignes vides. Je note qu’il y a un espace à l’intérieur, alors je les vire …

    Ensuite j’ai un « redir error », apparemment il n’aime pas les 2>&1 à la fin. Cela correspond à quoi ?

    Bon j’essaie de l’enlever, et alors j’obtiens « mirror: not connected »

    J’essaie donc de lancer la commande en direct, elle fonctionne … j’ai donc essayé de tourner autour de ton conseil sur l’encodage, je l’ai modifié en utf-8 sans bom mais rien n’y fait, j’ai toujours cette erreur

    Ce qui me fait aussi penser au soucis d’encodage c’est le fichier de log, son extention n’est pas « txt » mais « txt » avec deux especes de tabulations derrières.

    Mais je tourne en rond, impossible de l’avoir correctement.

    Serais il possible de mettre en téléchargement un fichier directement ?

  2. #2 by Eric on 24/08/2014 - 9 h 30 min

    tentative cette fois ci en modifiant directement la ligne de commande dans le script et pas juste dans la console, cela fonctionne bien.

    Donc cela provient bien je pense des paramètres qui sont mal encodés à l’exécution (voir passage sur le fichier de log aussi)

    Une idée pour me permettre de garder cela avec des paramètres plutot qu’en dur dans le script ?

    Merci

  3. #3 by Maël on 24/08/2014 - 10 h 24 min

    Bonjour Eric,

    pour le 2>&1 c’est une redirection des erreurs vers la sortie standard (gestion des logs)

    J’ai l’impression que ton copier/coller du code n’a pas été très bonne. Je vais déposer mes scripts sur le site pour que tu puisses les télécharger.

    Pour les paramètres, si tu les mets en début de script, normalement, tu ne devrais pas avoir de problème. (pas d’espace dans le mot de passe)

    Temporairement, affiche les paramètres dans la log

    echo ${servFTP} >> ${ficLog}
    echo ${userFTP} >> ${ficLog}
    echo ${passFTP} >> ${ficLog}
    
  4. #4 by Eric on 24/08/2014 - 10 h 48 min

    Merci, j’attends la mise en place des scripts sur le site pour les télécharger et essayer de les mettre en place

  5. #5 by Eric on 24/08/2014 - 11 h 06 min

    bien que je pense devoir trouver une autre solution, mon syno est un 410j et ça fait 1h30 que le script tourne … je pense qu’il mettra plus de 4h à s’exécuter.

    Il va falloir que je mette en place une solution incrémentale, mais j’attends avec impatience tes scripts

  6. #6 by Maël on 24/08/2014 - 12 h 06 min

    j’ai mis le 1er en téléchargement dans l’article

    http://www.cobestran.com/download/SvgCobestran.sh

    le script fait du miroir donc il est long la 1ère fois et pour les suivants, il ne copie que les changements.

  7. #7 by Eric on 24/08/2014 - 12 h 14 min

    Impeccable, j’ai juste mis à jour les paramètres et commenté la partie mail … et ça tourne.

    Dis moi, tu sais comment configurer un smtp externe avec authentification ? Je n’utilise pas l’accès de mon provider, j’utilise toujours le smtp de mon domaine … mais faut donc une authentification …

  8. #8 by Eric on 24/08/2014 - 12 h 15 min

    et le fichier de log n’a plus d’extension bizarre. C’était donc bien mon coper coller qui posait soucis.

  9. #9 by Maël on 25/08/2014 - 11 h 46 min

    Pour ta partie mail en smtp, je ne connais pas trop ton architecture donc je te propose la commande mail ou sinon ça qui marche sur toutes les plateformes. https://github.com/muquit/mailsend/

  10. #10 by louis on 30/09/2014 - 23 h 55 min

    Merci pour le tuto, très efficace j’ai modifier deux ou truc pour mieux coller à mes serveurs…

    Aussi dans tes Pré requis n’oublie pas de rajouter qu’il faut installer le package perl dans le centre des paquets pour utiliser ton script d’envoi de mail.

    Merci encore

  11. #11 by Maël on 23/03/2016 - 22 h 57 min

    Hello, afin d’actualiser le sujet, sur mon DS713+, lftp est inclus à l’installation. et il suffit de planifier la tache par l’interface web :-p
    et d’installer perl pour l’envoi par mail 😉

(ne sera pas publié)