[duvida] - Backups programados de um site

JPCarvalhinho

Power Member
Estou a participar num projecto grandinho e estou com algum receio que alguém faça asneira e como tal pretendo fazer backups diários dos htmls e do mysql do site...

Sei que posso ir diariamente ao cpanel e clicar na área de backup e fazer a coisa manualmente...

Mas e se eu quizer fazer um backup automático às tantas horas da noite para não interferir com algum visitante?

Encontrei duas opções:

1- Usar os comandos CRON programando alguns trabalhos de compressão e de transmissão por ftp para outro site...-> vou ter que pesquisar os comandos na net...

2- Uma aplicação externa tipo http://www.site-vault.com/ que faz o que quero para um disco local... mas que não tenho qualquer feedback.... mas facilmente passo para o cliente para ele manter.


O que vocês aconselham?

Cumps
JPC
 
Assim por alto, ocorre-me uma coisa:
Porque não fazeres um script, talvez em PHP, que fizesse o dump da bd para uma pasta fora do /www, e depois fazias um gzip do /www mais o .sql para outro ficheiro nessa pasta, e com o fsockopen ligavas-te por FTP ao outro servidor e enviavas o .gz?
Assim, o cronjob podia ser configurado para ser executado perto das 5 da manhã, e só tinha de executar um PHP.

Foi a primeira coisa que me ocorreu, mas pode ser que haja alguma forma melhor :x
 
O projecto não é alojado por uma empresa? Geralmente as empresas de alojamento fazem vários backups, mas pelo menos diários
 
Assim por alto, ocorre-me uma coisa:
Porque não fazeres um script, talvez em PHP, que fizesse o dump da bd para uma pasta fora do /www, e depois fazias um gzip do /www mais o .sql para outro ficheiro nessa pasta, e com o fsockopen ligavas-te por FTP ao outro servidor e enviavas o .gz?
Assim, o cronjob podia ser configurado para ser executado perto das 5 da manhã, e só tinha de executar um PHP.

Foi a primeira coisa que me ocorreu, mas pode ser que haja alguma forma melhor :x

...e depois contratam um gnomo para todos os dias aceder ao script que faz o trabalho. :P

É o único problema da tua solução: garantir periodicidade. Claro que este script pode ser feito em php e depois simplesmente fazer um cronjob que faz: php backup_script.php todos os dias :)
 
...e depois contratam um gnomo para todos os dias aceder ao script que faz o trabalho. :P

É o único problema da tua solução: garantir periodicidade. Claro que este script pode ser feito em php e depois simplesmente fazer um cronjob que faz: php backup_script.php todos os dias :)
Mas foi isso que propus - o script em php, e o cronjob era configurado para executar o PHP.
O que é que me está a escapar?
 
Aqui fica um sugestão em Perl.

Código:
#!/usr/bin/perl -T
#==========================================================================
#
#         FILE:  backup.pl
#
#        USAGE:  ./backup.pl -T (depois de tornar o script executável: 'chmod +x backup.pl')
#
#  DESCRIPTION:  Backup de ficheiros (recursivo) para tar.gz
#                Dump de base de dados mysql (sql -> tar.gz)
#                Envia ficheiros para servidor FTP
#                Envia mail com tempo de execução do backup
#
#      OPTIONS:  ---
# REQUIREMENTS:  Net::FTP
#                Mail::Sendmail
#         BUGS:  ---
#        NOTES:  O backup é composto por dois ficheiros: <DATA>_files.tar.gz e <DATA>_mysql.tar.gz.
#                Desta forma facilita-se o acesso a um ou a outro consoante a necessidade.
#       AUTHOR:  slack_guy @ TZ
#      VERSION:  0.1
#      CREATED:  09-08-2008 12:15:27 WEST
#==========================================================================
#  This program comes with NO WARRANTY, to the extent permitted by law.
#==========================================================================
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#==========================================================================
#

use strict;
use warnings;

$ENV{'PATH'} = '/usr/local/bin:/usr/bin';

use Time::HiRes qw/gettimeofday tv_interval/;

my $time_start = [gettimeofday];

my $data = data();

#==========================================================================
# Definições: modifica os parâmetros de acordo com o teu sistema
my $defs = {
    ftp_server     => 'ftp.example.com',
    ftp_user       => 'ftp_username',
    ftp_pass       => 'ftp_password',
    ftp_remote_dir => 'backups',

    mysql_user => 'mysql_username',
    mysql_pass => 'mysql_password',
    mysql_db   => 'mysql_database',

    # pastas a copiar
    dirs2backup => [
        '/home/me/www/xpto',
        '/home/you/www/xyz',
    ],

    # ficheiro de backup
    backup2file => "/home/me/tmp/${data}_files.tar.gz",

    # log temporario de ficheiros a copiar; é eliminado quando deixa de ser necessario
    temp_log_file => "/home/me/tmp/backup_$data.log",

    # ficheiro temporario com o dump da BD; é eliminado quando deixa de ser necessario
    temp_dump     => "/home/me/tmp/dump_$data.sql",

    # ficheiro com o dump da BD que vai ser transferido para o servidor remoto
    mysql_tar     => "/home/me/tmp/${data}_mysql.tar.gz",

    # qualquer expressao diferente de 'sim' equivale a 'nao'
    apagar_backups_locais => 'sim',

    mail_to      => '[email protected]',
    mail_from    => '[email protected]',
    mail_subject => "Backup de $data",
    mail_smtp    => 'mail.example.com', # ou 'localhost'
};

# A partir daqui não deverá ser necessário alterar mais nada.
#==========================================================================

my $cmds = {
    find       => '/usr/bin/find',
    tar        => '/bin/tar',
    mysql_dump => '/usr/bin/mysqldump',
};

dump_db();
backup();
send_ftp();

my $time_end = tv_interval( $time_start, [gettimeofday] );

send_mail();
finish();

exit 0;

sub finish {

    if (   $defs->{apagar_backups_locais}
        && $defs->{apagar_backups_locais} eq 'sim' )
    {
        unlink $defs->{backup2file};
        unlink $defs->{mysql_tar};
    }

    return;
}

sub send_ftp {

    use Net::FTP;

    my $ftp = Net::FTP->new( $defs->{ftp_server}, Debug => 0 )
      or die "Impossivel ligar ao servidor $defs->{ftp_server} : $@";

    $ftp->login( $defs->{ftp_user}, $defs->{ftp_pass} )
      or die "Impossivel entrar ", $ftp->message;

    $ftp->cwd( $defs->{ftp_remote_dir} )
      or die "Impossivel ir para a pasta $defs->{ftp_remote_dir} ",
      $ftp->message;

    $ftp->put( $defs->{backup2file} )
      or die "Impossivel copiar o ficheiro ", $ftp->message;

    $ftp->put( $defs->{mysql_tar} )
      or die "Impossivel copiar o ficheiro ", $ftp->message;

    $ftp->quit;

    return;
}

sub backup {

    my $pastas = $defs->{dirs2backup};

    # criamos um log com todas as pastas e ficheiros que vamos compactar
    foreach my $pasta (@$pastas) {
        my $cmd = qx|$cmds->{find} $pasta >> $defs->{temp_log_file}|;
    }

    # criamos o tar.gz com os ficheiros
    my $tgz = qx|$cmds->{tar} czpf $defs->{backup2file} -T $defs->{temp_log_file} 2>/dev/null|;

    # apagamos o log
    unlink $defs->{temp_log_file};

    return;
}

sub dump_db {

    # Dump da base de dados
    my $dump_cmd = qq|$cmds->{mysql_dump} --opt --user=$defs->{mysql_user} |;
    $dump_cmd .= qq|--password=$defs->{mysql_pass} $defs->{mysql_db} |;
    $dump_cmd .= qq| > $defs->{temp_dump}|;

    my $dump_mysql = qx|$dump_cmd|;

    # Compactar o dump da BD
    my $tgz =
      qx|$cmds->{tar} czfp $defs->{mysql_tar} $defs->{temp_dump} 2>/dev/null|;

    # Eliminar o dump temporario (ficheiro .sql)
    unlink $defs->{temp_dump};

    return;
}

sub data {

    use POSIX qw/strftime/;
    my $data = POSIX::strftime( "%F %T", localtime );
    $data =~ s/[\s\-:]/_/gmx;
    return $data;

}

sub send_mail {

    my $duracao = sprintf( "%.2f", $time_end );

    my %mail = (
        To      => $defs->{mail_to},
        From    => $defs->{mail_from},
        Subject => $defs->{mail_subject},
        Message => "Backup concluído em $duracao segundos\n",
        Smtp    => $defs->{mail_smtp},
    );

    use Mail::Sendmail;
    sendmail(%mail) or die $!;
    return;

}

Depois de testares (e testares e testares novamente!) e confirmares que está OK, podes pôr na crontab qualquer coisa como:
Código:
30 2 * * * /path/to/script/backup.pl -T 1>/dev/null
para executar o backup todos os dias às 2:30.

Dúvidas? Sugestões?

WARNING:
Nunca é demais avisar que as transferências por FTP não são seguras.
 
Última edição:
O projecto não é alojado por uma empresa? Geralmente as empresas de alojamento fazem vários backups, mas pelo menos diários

Nem todas.. Existem muitas que quando hà problemas os backups tem o condão de ter desaparecido. Acho que os clientes tem de começar a incluir nas suas perguntas iniciais se a empresa a quem contratam os seus planos tem algum plano de backup/disaster recovery.

O cliente fazer o seu próprio backup acaba por ser mais um layer de protecção para os seus dados.

Para não ficar totalmente offtopic fica aqui um script para backups automatizados do cPanel que já é usado por muitos clientes:

Criar um ficheiro fullbackup.php e colocar o seguinte conteudo:

Código:
<?php

// PHP script que permite backups automaticos e periodicos oara um servidor/conta remota.
// Este script contém passwords importantes.  MANTENHA ESTE FICHEIRO SEGURO! (coloque-o no directorio raiz e não no /www/)

// ********* OS SEGUINTES ITEMS NECESSITAM DE SER CONFIGURADOS *********

// Informação necessária para o acesso ao cPanel
$cpuser = "username"; // Username de login do CPanel
$cppass = "password"; // Password de login no CPanel
$domain = "examplo.com"; // nome do dominio onde corre o cpanel
$skin = "x3"; // Skin que é usada no cPanel

// Informação necessário para o FTP de destino
$ftpuser = "ftpusername"; // Username da conta FTP destino
$ftppass = "ftppassword"; // Password da conta FTP destino
$ftphost = "ftp.examplo.com"; // Nome completo do servidor ou Endereço IP do FTP de destino
$ftpmode = "ftp"; // Modo FTP ("ftp" para activo, "passiveftp" para passivo)

// Email para notificações
$notifyemail = "[email protected]"; // Endereço Email para envio dos resultados

// Modo seguro ou inseguro?
$secure = 0; // Colocar a 1 para SSL (requer suporte de SSL), de outro modo usa o HTTP

// Colocar a 1 para colocar os resultados da página web no log do cron
$debug = 0;

// *********** NENHUM DOS ITEMS A SEGUIR NECESSITA DE CONFIGURAÇÃO *********

if ($secure) {
   $url = "ssl://".$domain;
   $port = 2083;
} else {
   $url = $domain;
   $port = 2082;
}

$socket = fsockopen($url,$port);
if (!$socket) { echo "Falha a abrir o socket da ligação… Tchau!\n"; exit; }

// codificar a string de autenticação
$authstr = $cpuser.":".$cppass;
$pass = base64_encode($authstr);

$params = "dest=$ftpmode&email=$notifyemail&server=$ftphost&user=$ftpuser&pass=$ftppass&submit=Generate Backup";

// Fazer post ao cpanel
fputs($socket,"POST /frontend/".$skin."/backup/dofullbackup.html?".$params." HTTP/1.0\r\n");
fputs($socket,"Host: $domain\r\n");
fputs($socket,"Authorization: Basic $pass\r\n");
fputs($socket,"Connection: Close\r\n");
fputs($socket,"\r\n");

// Apanhar a resposta mesmo que nao seja necessario fazer nada com ela.
while (!feof($socket)) {
  $response = fgets($socket,4096);
  if ($debug) echo $response;
}

fclose($socket);

?>

Para programar o script de forma a este correr regularmente, salvar o código em cima num ficheiro backuptotal.php no seu directorio raiz (não o /public_html, que seria muito pouco sensato e seguro), e coloque no CronJobs/Trabalhos Cron uma linha como a que expomos a seguir:

Código:
15 2 * * * /usr/local/bin/php /home/youraccount/backuptotal.php

(Corre todas as noites às 2:15 da manhã)

ou

Código:
15 2 * * 1 /usr/local/bin/php /home/youraccount/fullbackup.php

(corre todos os domingos 2:15 da manhã)

O melhor horário para correr estes backups é entre as 2 e as 8 da manhã, de forma a que não cause carga no servidor e porque a essa hora o servidor está menos activo.

Espero que tenha ajudado e caso tenham alguma questão é só perguntar.

PS: Este script não é de nossa/minha autoria, mas desconheço quem seja o autor. No entanto todos os créditos para ele.

Saudações
 
Santo38, por uma questão de curiosidade, o que quer dizer cada "campo" nisso do cronjob? i.e.,
Código:
15 2 * * 1 /usr/local/bin/php /home/youraccount/fullbackup.php
minuto hora ? ? ? caminho_do_executável parâmetros?

Em relação ao próprio script, tens ali um echo (if(!$socket)) que talvez fosse melhor transformar num fopen("errors.log", "a+"). Assim, em vez de um echo que ninguém ia ler, existiria um registo de erros, que, passando para um nível seguinte, podia transformar-se num mail() para o responsável pelo site.
 
Wikipedia disse:
Fields

# +---------------- minute (0 - 59)
# | +------------- hour (0 - 23)
# | | +---------- day of month (1 - 31)
# | | | +------- month (1 - 12)
# | | | | +---- day of week (0 - 7) (Sunday=0 or 7)
# | | | | |
* * * * * command to be executed

Kayvlim, sorry pelo off-topic mas como metes esses links todos "pipis" nos nomes das pessoas? :)
 
Kayvlim, sorry pelo off-topic mas como metes esses links todos "pipis" nos nomes das pessoas? :)
Ups, não procurei mesmo por preguiça :x obrigado :x

Quanto aos nicks, apenas faço copy/paste e uso o editor WYSIWYG, que o Firefox (3, neste caso, mas o 2 também serve) trata do resto :P

/offtopic
 
Santo38,
Em relação ao próprio script, tens ali um echo (if(!$socket)) que talvez fosse melhor transformar num fopen("errors.log", "a+"). Assim, em vez de um echo que ninguém ia ler, existiria um registo de erros, que, passando para um nível seguinte, podia transformar-se num mail() para o responsável pelo site.

A ideia é só fazer log se o debug estiver activo. No entanto a tua sugestão é boa. Usar a função numa condição de erro e enviar o resultado por mail ao cliente..

Tudo o que melhore este script, que diga-se de passagem funciona muito bem, é sempre util.

Saudações
 
Já agora, mais uma questão de pormenor:
De acordo com o que o _freelancer_ colocou, «day of week (0 - 7) (Sunday=0 or 7)»; no entanto, na linha do cronjob que o Santo38 colocou, usou o valor 1 para indicar Domingo. Assim sendo, afinal, qual dos dois está correcto?

edit - ah, calma, será que o Santo38 queria dizer com "domingo" a madrugada de Domingo para Segunda, sendo que por essa altura já interessa ser o valor para Segunda? :x
 
Última edição:
lol... já fiz isso de uma maneira mais fácil, gravei a input do teclado e do rato e depois foi só "reproduzir" e ele fazia automaticamente. é o método mais "fácil" (e pregiçoso :P) de fazer isso
 
Já agora por curiosidade...

É possivel (para páginas pequenas, claro) que o script envie o backup por e-mail para uma conta pré-definida?
 
Sim, dado que o backup é gravado no servidor, acho que se pode fazer com que o script no fim envie um e-mail com o gzip anexado :)
 
Back
Topo