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.
- Um script
backup-dados.shque copia uma pasta comrsyncpara 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.
| Item | Detalhe |
|---|---|
| Tempo estimado | 1h |
| Pré-requisitos | Como Usar os Projetos, Primeiro Script, scp e rsync, Criar um Serviço, Backup |
| Onde roda | VM lab do Multipass (prompt ubuntu@lab) |
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
-
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 filesO
head -c 1M /dev/urandompega 1 MB de bytes aleatórios; é um jeito rápido de criar um arquivo "pesado". Se otreenão existir, instale comsudo apt install -y tree.Confira se deu certo:
du -sh ~/dadosdeve mostrar cerca de1.1M. -
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:
Trecho Por 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 logquando 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 orm -rfdentro de scriptsO
findestá limitado a/backup, a um nível de profundidade (-maxdepth 1) e a nomes que começam com20. Nunca rode umrm -rfcom variável sem essas travas: se$DESTINOestivesse 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 comsudo rm -r /backup/2026-10-15_1052. -
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_0200não aparece mais, e2026-10-12_0200continua lá. -
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
Linha Significado 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. dailyseria 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
Persistente semOnFailure:$ sudo crontab -e
0 2 * * * /usr/local/bin/backup-dados.sh
Veja Agendar Tarefas (cron).
-
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-falhouregistra 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%Fdodate), é preciso dobrar:%%F.Agora vamos provocar uma falha. O
chattr +itorna 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 doExecStartdobackup-falhou.service.Se deu errado: o backup falhou mas o aviso não apareceuComo confirmar:
systemctl status backup-falhou.service. Se ele nem rodou, confira se o nome noOnFailure=é idêntico ao do arquivo e se você rodousudo systemctl daemon-reloaddepois de criar os arquivos. -
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 -1funciona porque os nomes começam pela data: o último em ordem alfabética é o mais recente. Ocp -apreserva 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
sha256sumcalcula 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çasO 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), atualizeULTIMOe repita a comparação.
O que você aprendeu
- Escrever um script robusto com
set -euo pipefail, log etrap … ERR. - Copiar com
rsync -ae entender a barra final. - Apagar backups antigos com
find -mtimede forma segura. - Criar um service e um timer do systemd, com
PersistenteOnFailure. - 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 -resha256sum.
Desafios extras
- Use
rsync --link-destpara que arquivos que não mudaram não ocupem espaço de novo em cada cópia. - Mande o backup para outra VM por SSH:
rsync -a -e ssh … ubuntu@IP:/backup/. - Compacte cada backup com
tare compare o espaço usado. - 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:
2. Habilitar o agendamento
Complete para ligar o timer agora e em todo boot:
3. Qual é a diferença entre rsync -a dados/ destino/ e rsync -a dados destino/?
4. Quando você pode dizer que o backup funciona?