Projeto Backup Automático

Um backup que você precisa lembrar de fazer não é backup. E um backup que nunca foi restaurado é só uma esperança. Neste laboratório você monta uma rotina que copia os dados todo dia sozinha, apaga cópias velhas, avisa quando falha, e, o mais importante, prova que a restauração funciona.

Ao terminar você terá
  • Um script backup-dados.sh que copia uma pasta com rsync para uma pasta com a data no nome.
  • Um log com o resultado de cada execução.
  • Rotação: cópias com mais de 7 dias são apagadas sozinhas.
  • Um systemd timer que roda o backup todo dia às 02:00, e um aviso quando ele falhar.
  • Uma restauração testada, arquivo por arquivo.
ItemDetalhe
Tempo estimado1h
Pré-requisitosComo Usar os Projetos, Primeiro Script, scp e rsync, Criar um Serviço, Backup
Onde rodaVM lab do Multipass (prompt ubuntu@lab)
No mundo real

Aqui a pasta /backup fica no mesmo disco, para simplificar. Na vida real, o destino deve ser outro disco (HD externo, outro servidor). Backup no mesmo disco não sobrevive a um disco queimado. Veja a regra 3-2-1 em Backup.


As etapas

  1. Preparar a VM e os dados de exemplo

    O que vamos fazer e por quê: criar dados para proteger. Usamos arquivos de texto (fáceis de conferir) e um arquivo binário de 1 MB, simulando uma foto.

    $ multipass launch 26.04 --name lab --disk 10G --memory 2G
    Launched: lab
    $ multipass shell lab
    $ mkdir -p ~/dados/{contratos,fotos}
    $ for i in 1 2 3; do echo "Contrato número $i" > ~/dados/contratos/contrato-0$i.txt; done
    $ head -c 1M /dev/urandom > ~/dados/fotos/foto1.jpg
    $ tree ~/dados
    /home/ubuntu/dados
    ├── contratos
    │   ├── contrato-01.txt
    │   ├── contrato-02.txt
    │   └── contrato-03.txt
    └── fotos
        └── foto1.jpg
    
    3 directories, 4 files

    O head -c 1M /dev/urandom pega 1 MB de bytes aleatórios; é um jeito rápido de criar um arquivo "pesado". Se o tree não existir, instale com sudo apt install -y tree.

    Confira se deu certo: du -sh ~/dados deve mostrar cerca de 1.1M.

  2. Escrever o script de backup

    O que vamos fazer e por quê: juntar num arquivo tudo o que o backup precisa fazer. Assim o comando é sempre o mesmo, seja você ou o agendador que o executa.

    $ sudo nano /usr/local/bin/backup-dados.sh
    #!/usr/bin/env bash
    # Backup diário de /home/ubuntu/dados, com log e rotação de 7 dias.
    set -euo pipefail                    # para no primeiro erro
    
    ORIGEM="/home/ubuntu/dados/"         # a barra final copia o CONTEÚDO da pasta
    DESTINO="/backup"
    DIAS=7                               # quantos dias guardar
    LOG="/var/log/backup-dados.log"
    AGORA=$(date +%F_%H%M)               # ex.: 2026-10-15_0200
    
    log() { echo "$(date '+%F %T') $*" >> "$LOG"; }
    trap 'log "FALHOU na linha $LINENO"' ERR   # se algo der erro, registra antes de sair
    
    log "início: $DESTINO/$AGORA"
    mkdir -p "$DESTINO/$AGORA"
    rsync -a "$ORIGEM" "$DESTINO/$AGORA/"
    
    # Rotação: apaga pastas de backup com mais de $DIAS dias
    find "$DESTINO" -mindepth 1 -maxdepth 1 -type d -name '20*' -mtime +"$DIAS" -exec rm -rf {} +
    
    log "ok: $(du -sh "$DESTINO/$AGORA" | cut -f1) copiados"

    Linha por linha, o que importa:

    TrechoPor quê
    set -euo pipefailSem isso, um erro no meio passaria despercebido e o log diria "ok". Veja Primeiro Script.
    "/home/ubuntu/dados/"Com a barra final, o rsync copia o conteúdo. Sem ela, criaria …/dados/dados.
    date +%F_%H%MNome que se ordena sozinho por data: 2026-10-15_0200.
    trap '…' ERRRoda o log quando qualquer comando falha.
    rsync -aModo arquivo: preserva datas, donos e permissões.
    find … -mtime +7 -exec rm -rf {} +Acha pastas modificadas há mais de 7 dias e apaga.
    Cuidado com o rm -rf dentro de scripts

    O find está limitado a /backup, a um nível de profundidade (-maxdepth 1) e a nomes que começam com 20. Nunca rode um rm -rf com variável sem essas travas: se $DESTINO estivesse vazio, o comando apagaria outro lugar.

    Dê permissão de execução e rode o script pela primeira vez, à mão:

    $ sudo chmod 755 /usr/local/bin/backup-dados.sh
    $ sudo /usr/local/bin/backup-dados.sh
    $ echo $?
    0                                                 « 0 = terminou sem erro

    Confira se deu certo:

    $ ls /backup
    2026-10-15_1052
    $ cat /var/log/backup-dados.log
    2026-10-15 10:52:31 início: /backup/2026-10-15_1052
    2026-10-15 10:52:31 ok: 1.1M copiados
    $ diff -r ~/dados /backup/2026-10-15_1052 && echo "iguais"
    iguais                                            « diff não achou nenhuma diferença
    Se deu errado: "rsync: command not found"

    Como resolver: sudo apt install -y rsync. Depois rode o script de novo.

    Se deu errado: apareceu /backup/2026-10-15_1052/dados/

    O que aconteceu: faltou a barra no fim de ORIGEM.

    Como resolver: corrija para "/home/ubuntu/dados/" e apague a pasta errada com sudo rm -r /backup/2026-10-15_1052.

  3. Testar a rotação

    O que vamos fazer e por quê: não dá para esperar 8 dias para ver se a limpeza funciona. Vamos criar pastas "antigas" falsificando a data com touch -d.

    $ sudo mkdir /backup/2026-09-30_0200 /backup/2026-10-12_0200
    $ sudo touch -d "15 days ago" /backup/2026-09-30_0200
    $ sudo touch -d "3 days ago" /backup/2026-10-12_0200
    $ sudo /usr/local/bin/backup-dados.sh
    $ ls /backup
    2026-10-12_0200  2026-10-15_1052  2026-10-15_1054   « a de 15 dias sumiu; a de 3 dias ficou

    Confira se deu certo: 2026-09-30_0200 não aparece mais, e 2026-10-12_0200 continua lá.

  4. Agendar com um systemd timer

    O que vamos fazer e por quê: um timer é o despertador do systemd. Ele chama um service no horário marcado. Comparado ao cron, ele tem duas vantagens: guarda o log no journal e, com Persistent=true, roda o backup atrasado se a máquina estava desligada às 02:00.

    Primeiro, o serviço, que diz o que rodar:

    $ sudo nano /etc/systemd/system/backup-dados.service
    [Unit]
    Description=Backup da pasta dados
    OnFailure=backup-falhou.service
    
    [Service]
    Type=oneshot
    ExecStart=/usr/local/bin/backup-dados.sh

    Depois, o timer, que diz quando:

    $ sudo nano /etc/systemd/system/backup-dados.timer
    [Unit]
    Description=Backup diário às 02:00
    
    [Timer]
    OnCalendar=*-*-* 02:00:00
    Persistent=true
    
    [Install]
    WantedBy=timers.target
    LinhaSignificado
    Type=oneshotO serviço roda, termina e pronto; não fica rodando como um servidor.
    OnFailure=Se o serviço falhar, ativa outro serviço (o aviso, na próxima etapa).
    OnCalendar=*-*-* 02:00:00Qualquer ano, mês e dia, às 02:00. daily seria meia-noite.
    Persistent=trueSe a máquina estava desligada no horário, roda assim que ligar.
    $ sudo systemctl daemon-reload
    $ sudo systemctl enable --now backup-dados.timer
    Created symlink '/etc/systemd/system/timers.target.wants/backup-dados.timer' → '/etc/systemd/system/backup-dados.timer'.

    Repare: quem é habilitado é o timer, não o service. O timer é que chama o service.

    Confira se deu certo:

    $ systemctl list-timers backup-dados.timer
    NEXT                         LEFT LAST PASSED UNIT               ACTIVATES
    Fri 2026-10-16 02:00:00 UTC   15h -    -      backup-dados.timer backup-dados.service
    
    1 timers listed.
    $ sudo systemctl start backup-dados.service
    « roda agora, sem esperar as 02:00
    $ journalctl -u backup-dados.service -n 3 --no-pager
    Oct 15 11:03:10 lab systemd[1]: Starting backup-dados.service - Backup da pasta dados...
    Oct 15 11:03:10 lab systemd[1]: backup-dados.service: Deactivated successfully.
    Oct 15 11:03:10 lab systemd[1]: Finished backup-dados.service - Backup da pasta dados.
    Prefere cron? A forma equivalente

    Uma linha no crontab do root faz o agendamento, mas sem Persistent e sem OnFailure:

    $ sudo crontab -e
    0 2 * * * /usr/local/bin/backup-dados.sh

    Veja Agendar Tarefas (cron).

  5. Ser avisado quando falhar

    O que vamos fazer e por quê: um backup que falha em silêncio é o pior cenário: você descobre só quando precisa dele. O serviço backup-falhou registra um erro em destaque no journal e no log do backup.

    $ sudo nano /etc/systemd/system/backup-falhou.service
    [Unit]
    Description=Aviso de falha no backup
    
    [Service]
    Type=oneshot
    ExecStart=/usr/bin/logger -p user.err -t backup "FALHA no backup-dados. Veja: journalctl -u backup-dados"
    ExecStart=/usr/bin/sh -c 'echo "$(date "+%%F %%T") ALERTA: o serviço de backup falhou" >> /var/log/backup-dados.log'
    Por que %%?

    Dentro de arquivos do systemd, % tem significado especial. Para escrever um % de verdade (como em %F do date), é preciso dobrar: %%F.

    Agora vamos provocar uma falha. O chattr +i torna a pasta imutável: nem o root consegue criar nada dentro dela.

    $ sudo systemctl daemon-reload
    $ sudo chattr +i /backup
    $ sudo systemctl start backup-dados.service
    Job for backup-dados.service failed because the control process exited with error code.
    See "systemctl status backup-dados.service" and "journalctl -xeu backup-dados.service" for details.

    Confira se deu certo: o aviso precisa aparecer em dois lugares:

    $ journalctl -t backup -n 1 --no-pager
    Oct 15 11:10:42 lab backup[2214]: FALHA no backup-dados. Veja: journalctl -u backup-dados
    $ tail -3 /var/log/backup-dados.log
    2026-10-15 11:10:42 início: /backup/2026-10-15_1110
    2026-10-15 11:10:42 FALHOU na linha 15
    2026-10-15 11:10:42 ALERTA: o serviço de backup falhou
    $ sudo chattr -i /backup
    « desfaz a "pane"

    Num servidor de verdade, o próximo passo seria mandar esse aviso por e-mail (com msmtp) ou para um chat. A estrutura é a mesma: troque o comando do ExecStart do backup-falhou.service.

    Se deu errado: o backup falhou mas o aviso não apareceu

    Como confirmar: systemctl status backup-falhou.service. Se ele nem rodou, confira se o nome no OnFailure= é idêntico ao do arquivo e se você rodou sudo systemctl daemon-reload depois de criar os arquivos.

  6. Testar a restauração (obrigatório)

    O que vamos fazer e por quê: simular o dia em que alguém apaga um arquivo importante, e trazê-lo de volta. Depois, restaurar tudo numa pasta separada e comparar com o original. Só um backup restaurado com sucesso é um backup confiável.

    Recuperar um arquivo apagado

    $ rm ~/dados/contratos/contrato-02.txt
    $ ls ~/dados/contratos
    contrato-01.txt  contrato-03.txt                   « o 02 sumiu
    $ ULTIMO=$(ls -1 /backup | tail -1)
    $ echo $ULTIMO
    2026-10-15_1103
    $ cp -a /backup/$ULTIMO/contratos/contrato-02.txt ~/dados/contratos/
    $ cat ~/dados/contratos/contrato-02.txt
    Contrato número 2                                 « voltou, com o conteúdo certo

    O ls -1 /backup | tail -1 funciona porque os nomes começam pela data: o último em ordem alfabética é o mais recente. O cp -a preserva data e dono do arquivo original.

    Restaurar tudo e comparar

    $ rsync -a /backup/$ULTIMO/ /tmp/restaurado/
    $ diff -r ~/dados /tmp/restaurado && echo "RESTAURAÇÃO OK"
    RESTAURAÇÃO OK
    $ sha256sum ~/dados/fotos/foto1.jpg /tmp/restaurado/fotos/foto1.jpg
    5f2c…a91e  /home/ubuntu/dados/fotos/foto1.jpg
    5f2c…a91e  /tmp/restaurado/fotos/foto1.jpg      « o mesmo código = arquivos idênticos, byte a byte

    O sha256sum calcula uma "impressão digital" do arquivo. Se um único byte mudasse, o código seria completamente outro. É a prova de que a foto voltou intacta.

    Se deu errado: o diff mostra diferenças

    O que aconteceu: o backup foi feito antes de você mudar algum arquivo, ou faltou a barra final em algum dos caminhos do rsync.

    Como resolver: rode o backup de novo (sudo systemctl start backup-dados.service), atualize ULTIMO e repita a comparação.


O que você aprendeu

  • Escrever um script robusto com set -euo pipefail, log e trap … ERR.
  • Copiar com rsync -a e entender a barra final.
  • Apagar backups antigos com find -mtime de forma segura.
  • Criar um service e um timer do systemd, com Persistent e OnFailure.
  • Provocar uma falha de propósito para testar o aviso.
  • Restaurar um arquivo e o backup inteiro, e provar que estão idênticos com diff -r e sha256sum.

Desafios extras

  1. Use rsync --link-dest para que arquivos que não mudaram não ocupem espaço de novo em cada cópia.
  2. Mande o backup para outra VM por SSH: rsync -a -e ssh … ubuntu@IP:/backup/.
  3. Compacte cada backup com tar e compare o espaço usado.
  4. Experimente o restic, que faz backup com deduplicação e criptografia.

Desfazer e limpar

$ sudo systemctl disable --now backup-dados.timer
$ sudo rm /etc/systemd/system/backup-{dados,falhou}.service /etc/systemd/system/backup-dados.timer
$ sudo systemctl daemon-reload
$ exit
$ multipass delete --purge lab

Exercícios

1. Nome com data

Complete para gerar um nome como 2026-10-15:

date +

2. Habilitar o agendamento

Complete para ligar o timer agora e em todo boot:

sudo systemctl enable backup-dados.timer

3. Qual é a diferença entre rsync -a dados/ destino/ e rsync -a dados destino/?

4. Quando você pode dizer que o backup funciona?