Guia
Como configurar backup automático com rsync e cron
Aprenda a configurar backups automáticos em uma VPS com rsync e cron, incluindo chaves SSH, retenção, logs, testes de restauração e diagnóstico seguro.
O que você vai aprender
Neste guia, você vai montar um sistema de backup automático para uma VPS Linux usando rsync e cron. O modelo cria snapshots diários em um disco ou volume separado montado em /mnt/backup. Arquivos que não mudaram são reaproveitados por hard links, reduzindo o consumo de espaço sem transformar cada snapshot em um backup incremental difícil de restaurar.
Ao concluir, você saberá:
- Instalar e validar
rsync,croneflockem Ubuntu ou Debian. - Confirmar que o volume de backup está realmente montado antes de copiar dados.
- Definir exclusões para diretórios virtuais e arquivos temporários.
- Executar uma simulação segura com
rsync --dry-run. - Criar snapshots completos com hard links para arquivos inalterados.
- Aplicar retenção automática sem remover diretórios fora do destino definido.
- Agendar o processo, consultar logs e realizar um teste de restauração.
Esse procedimento ajuda a proteger arquivos, configurações e conteúdo de aplicações. Ele não substitui uma cópia externa. Uma falha física, invasão ou problema no provedor pode afetar a VPS e um volume anexado ao mesmo ambiente. Para entender outras camadas de proteção, consulte o conteúdo sobre VPS com backup automático.
Pré-requisitos
Você precisa de acesso SSH a uma VPS Ubuntu ou Debian e de uma conta capaz de executar comandos com sudo. O guia usa caminhos e ferramentas disponíveis nessas distribuições. Em Rocky Linux, AlmaLinux ou CentOS, troque o apt por dnf, mas revise também a localização dos serviços e as políticas do SELinux.
Prepare um volume separado e monte-o em /mnt/backup. Pode ser um disco adicional, armazenamento em rede confiável ou volume de bloco fornecido pela sua infraestrutura. Não use apenas uma pasta no mesmo sistema de arquivos da VPS, pois uma falha do disco principal eliminaria os dados originais e a cópia.
Confira seu usuário e os discos antes de alterar qualquer configuração:
whoami
sudo -v
lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINTS
findmnt /mnt/backup
Uma montagem válida deve produzir algo parecido com:
TARGET SOURCE FSTYPE OPTIONS
/mnt/backup /dev/sdb1 ext4 rw,relatime
Se findmnt não retornar nada, interrompa o procedimento e monte o volume corretamente. O script será configurado para falhar quando o destino não estiver montado, evitando gravar backups no disco principal por engano.
Se já existirem um script ou uma tarefa com os mesmos nomes, faça uma cópia antes de continuar:
sudo test ! -f /usr/local/sbin/backup-rsync || sudo cp -a /usr/local/sbin/backup-rsync "/root/backup-rsync.pre-guia.$(date +%F-%H%M%S)"
sudo test ! -f /etc/cron.d/rsync-backup || sudo cp -a /etc/cron.d/rsync-backup "/root/rsync-backup.cron.pre-guia.$(date +%F-%H%M%S)"
Esses comandos não substituem arquivos existentes. Você também deve ter espaço livre suficiente no destino. Como referência inicial, reserve pelo menos o tamanho atualmente utilizado no sistema de origem, mais a margem necessária para arquivos alterados durante a retenção.
Passo 1: Verificar o servidor e instalar as ferramentas
Comece identificando a distribuição. Isso evita executar comandos de instalação incompatíveis:
cat /etc/os-release | grep -E '^(NAME|VERSION)='
Em Ubuntu 24.04, a saída será semelhante a:
NAME="Ubuntu"
VERSION="24.04 LTS (Noble Numbat)"
Atualize o índice de pacotes e instale rsync e cron. O pacote util-linux, normalmente instalado por padrão, fornece o comando flock usado para impedir duas execuções simultâneas:
sudo apt update
sudo apt install -y rsync cron util-linux
O final da instalação deve mostrar mensagens próximas destas:
Setting up rsync ...
Setting up cron ...
Processing triggers for man-db ...
Ative o serviço de agendamento e confirme seu estado:
sudo systemctl enable --now cron
sudo systemctl is-active cron
rsync --version | head -n 2
flock --version
O resultado esperado inclui:
active
rsync version 3.2.x protocol version 31
flock from util-linux 2.x
Antes de prosseguir, verifique novamente o destino e o espaço disponível. Essa checagem é necessária porque uma pasta /mnt/backup pode existir mesmo quando o volume não foi montado:
findmnt --mountpoint /mnt/backup
df -h / /mnt/backup
Você deve ver fontes diferentes para / e /mnt/backup. Se ambos apontarem para o mesmo dispositivo, o backup continuará útil contra exclusão acidental, mas não protegerá contra falha do disco. Corrija a montagem antes de automatizar.
Ambientes que hospedam comércio eletrônico exigem cuidado adicional com bancos de dados e arquivos enviados durante a cópia. Consulte os requisitos comuns de uma VPS para loja virtual e planeje dumps consistentes do banco. O rsync copia arquivos, mas não garante sozinho a consistência transacional de MySQL ou PostgreSQL em execução.
Passo 2: Preparar o destino e as exclusões
Agora crie a estrutura onde os snapshots e logs serão armazenados. Use permissões restritas, pois os backups podem conter configurações, chaves privadas e credenciais de aplicações:
sudo install -d -m 700 -o root -g root /mnt/backup/rsync-snapshots
sudo install -d -m 750 -o root -g adm /var/log/rsync-backup
sudo touch /var/log/rsync-backup/backup.log
sudo chown root:adm /var/log/rsync-backup/backup.log
sudo chmod 640 /var/log/rsync-backup/backup.log
Confira o resultado:
sudo stat -c '%A %U:%G %n' /mnt/backup/rsync-snapshots /var/log/rsync-backup /var/log/rsync-backup/backup.log
A saída esperada será parecida com:
drwx------ root:root /mnt/backup/rsync-snapshots
drwxr-x--- root:adm /var/log/rsync-backup
-rw-r----- root:adm /var/log/rsync-backup/backup.log
Crie a lista de exclusões. Ela impede recursão no próprio destino e ignora sistemas de arquivos virtuais, temporários e dados que não devem ser copiados como arquivos comuns:
sudo tee /etc/rsync-backup.exclude > /dev/null <<'EOF'
/proc/***
/sys/***
/dev/***
/run/***
/tmp/***
/mnt/***
/media/***
/lost+found
/swapfile
/var/tmp/***
EOF
Verifique o arquivo antes de usá-lo:
sudo cat /etc/rsync-backup.exclude
Você deve ver exatamente os caminhos informados. O padrão /*** exclui o diretório e todo o conteúdo abaixo dele. Como /mnt/*** está excluído, o rsync não tentará copiar os snapshots para dentro de novos snapshots.
Não exclua /var/lib/mysql ou /var/lib/postgresql pensando que isso resolve a consistência do banco. Gere dumps separados com as ferramentas do banco e salve-os em um diretório incluído no backup. Se sua aplicação grava arquivos continuamente, escolha um horário de menor movimento ou use snapshots do sistema de arquivos em conjunto com o rsync.
Passo 3: Executar um backup manual de teste
Antes de copiar qualquer dado, faça uma simulação. O --dry-run lista o que seria transferido sem escrever arquivos no destino. A opção --one-file-system evita atravessar outros sistemas de arquivos montados abaixo de /, como volumes de aplicações que você ainda não decidiu incluir:
sudo rsync -aAXHn --numeric-ids --one-file-system --exclude-from=/etc/rsync-backup.exclude --stats / /mnt/backup/rsync-snapshots/teste-manual/
O comando pode listar muitos caminhos. No final, procure estatísticas semelhantes a estas:
Number of files: 48,321
Number of regular files transferred: 31,204
Total file size: 6.42G bytes
Total transferred file size: 6.42G bytes
Literal data: 0 bytes
Como a execução é simulada, Literal data deve permanecer em zero. Confirme também que caminhos como /proc, /sys, /dev e /mnt/backup não aparecem na lista de arquivos transferidos.
Calcule quanto espaço a origem utiliza e compare com o destino:
sudo du -xsh /
df -h /mnt/backup
Um resultado possível é:
6.8G /
Filesystem Size Used Avail Use% Mounted on
/dev/sdb1 50G 1.2G 46G 3% /mnt/backup
Se o espaço disponível for menor que o uso da origem, não execute a cópia real. Amplie o volume, reduza o escopo ou revise as exclusões. Também verifique se há arquivos de cache muito grandes com sudo du -xhd1 /var | sort -h.
Para validar que o destino aceita gravação, crie e remova apenas um arquivo de teste controlado:
sudo touch /mnt/backup/rsync-snapshots/.write-test
sudo test -w /mnt/backup/rsync-snapshots && echo 'Destino gravável'
sudo rm /mnt/backup/rsync-snapshots/.write-test
A saída esperada é:
Destino gravável
O rm acima remove somente o arquivo de teste recém-criado. Não adapte o caminho sem conferir o destino com findmnt e ls -la.
Passo 4: Criar o script de backup com retenção
O script abaixo cria um diretório datado, reutiliza arquivos inalterados do snapshot anterior e mantém sete snapshots completos. Cada diretório pode ser restaurado de forma independente, embora arquivos iguais compartilhem os mesmos dados físicos por hard links.
Atenção: a rotina de retenção contém rm -rf e remove snapshots antigos. Ela valida o nome e limita a operação a /mnt/backup/rsync-snapshots. Não mude DEST_ROOT sem revisar todas as proteções.
Crie o script:
sudo tee /usr/local/sbin/backup-rsync > /dev/null <<'EOF'
#!/usr/bin/env bash
set -Eeuo pipefail
DEST_ROOT="/mnt/backup/rsync-snapshots"
LOG="/var/log/rsync-backup/backup.log"
STAMP="$(date +%F_%H-%M-%S)"
SNAPSHOT="$DEST_ROOT/$STAMP"
RETENTION=7
exec >>"$LOG" 2>&1
echo "[$(date --iso-8601=seconds)] Início do backup"
if ! mountpoint -q /mnt/backup; then
echo "ERRO: /mnt/backup não está montado"
exit 1
fi
mkdir -p "$SNAPSHOT"
LATEST="$(readlink -f "$DEST_ROOT/current" 2>/dev/null || true)"
RSYNC_ARGS=(-aAXH --numeric-ids --one-file-system --exclude-from=/etc/rsync-backup.exclude)
if [[ -n "$LATEST" && -d "$LATEST" ]]; then
RSYNC_ARGS+=(--link-dest="$LATEST")
fi
rsync "${RSYNC_ARGS[@]}" / "$SNAPSHOT/"
touch "$SNAPSHOT/.complete"
ln -sfn "$STAMP" "$DEST_ROOT/current"
mapfile -t OLD_SNAPSHOTS < <(find "$DEST_ROOT" -mindepth 1 -maxdepth 1 -type d -name '20??-??-??_??-??-??' -printf '%T@ %p\n' | sort -nr | tail -n +$((RETENTION + 1)) | cut -d' ' -f2-)
for old in "${OLD_SNAPSHOTS[@]}"; do
[[ "$old" == "$DEST_ROOT"/20??-??-??_??-??-?? ]] || exit 1
echo "Removendo snapshot antigo: $old"
rm -rf --one-file-system "$old"
done
echo "[$(date --iso-8601=seconds)] Backup concluído em $SNAPSHOT"
EOF
sudo chmod 750 /usr/local/sbin/backup-rsync
sudo chown root:root /usr/local/sbin/backup-rsync
Valide a sintaxe sem executar o backup:
sudo bash -n /usr/local/sbin/backup-rsync && echo 'Sintaxe válida'
sudo stat -c '%A %U:%G %n' /usr/local/sbin/backup-rsync
O resultado deve incluir:
Sintaxe válida
-rwxr-x--- root:root /usr/local/sbin/backup-rsync
Passo 5: Testar o script e revisar o snapshot
Execute o script manualmente antes de configurar o cron. A primeira cópia pode levar vários minutos, dependendo da quantidade de dados, velocidade do disco e número de arquivos:
sudo /usr/local/sbin/backup-rsync
sudo tail -n 20 /var/log/rsync-backup/backup.log
Quando tudo funcionar, o log terminará com linhas semelhantes a:
[2026-09-28T14:20:03+00:00] Início do backup
[2026-09-28T14:24:41+00:00] Backup concluído em /mnt/backup/rsync-snapshots/2026-09-28_14-20-03
Confira o link current, o marcador de conclusão e o espaço consumido:
sudo readlink -f /mnt/backup/rsync-snapshots/current
sudo test -f /mnt/backup/rsync-snapshots/current/.complete && echo 'Snapshot completo'
sudo du -sh /mnt/backup/rsync-snapshots/current
sudo ls -la /mnt/backup/rsync-snapshots/current | head
A saída esperada contém um caminho datado e a confirmação:
/mnt/backup/rsync-snapshots/2026-09-28_14-20-03
Snapshot completo
6.5G /mnt/backup/rsync-snapshots/current
Execute o script uma segunda vez para testar o uso de hard links. Depois, identifique um arquivo estável, como /etc/hostname, e compare o número do inode nos dois snapshots mais recentes:
sudo /usr/local/sbin/backup-rsync
sudo find /mnt/backup/rsync-snapshots -mindepth 1 -maxdepth 1 -type d -name '20??-*' -printf '%T@ %p\n' | sort -nr | head -n 2
sudo stat -c '%i %h %n' /mnt/backup/rsync-snapshots/20??-??-??_??-??-??/etc/hostname
Nos snapshots em que o arquivo não mudou, o inode será igual e a contagem de links será maior que um. Isso confirma que o --link-dest está economizando espaço.
Não edite arquivos dentro de um snapshot. Como arquivos inalterados podem compartilhar inodes, uma edição direta pode afetar mais de um snapshot. Trate todo o destino como somente leitura para atividades normais e restaure os dados copiando-os para outro local.
Passo 6: Agendar a execução com cron
Com o teste manual concluído, agende o backup para 02:15 todos os dias. O flock usa um arquivo de bloqueio e impede que uma nova execução comece se a anterior ainda estiver ativa:
sudo tee /etc/cron.d/rsync-backup > /dev/null <<'EOF'
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MAILTO=""
15 2 * * * root /usr/bin/flock -n /run/lock/rsync-backup.lock /usr/local/sbin/backup-rsync
EOF
sudo chown root:root /etc/cron.d/rsync-backup
sudo chmod 644 /etc/cron.d/rsync-backup
Arquivos dentro de /etc/cron.d precisam terminar com uma nova linha, usar permissões adequadas e informar o usuário após a expressão de horário. Verifique esses pontos:
sudo cat /etc/cron.d/rsync-backup
sudo stat -c '%A %U:%G %n' /etc/cron.d/rsync-backup
sudo systemctl is-active cron
Você deve obter:
-rw-r--r-- root:root /etc/cron.d/rsync-backup
active
Teste o mesmo comando utilizado pelo cron sem esperar até 02:15:
sudo /usr/bin/flock -n /run/lock/rsync-backup.lock /usr/local/sbin/backup-rsync
echo $?
O código esperado é 0. Em seguida, confira o log:
sudo tail -n 10 /var/log/rsync-backup/backup.log
Se você quiser observar uma execução real do cron durante a implantação, altere temporariamente o horário para alguns minutos à frente, aguarde e depois restaure 15 2 * * *. Evite uma expressão a cada minuto em servidores com muitos dados.
A seleção de horários, limites de retenção e critérios de teste deve acompanhar os riscos da aplicação. A página Como avaliamos serviços de VPS explica aspectos de infraestrutura que também influenciam disponibilidade e recuperação.
Verificação e testes
Um backup só pode ser considerado funcional depois de uma restauração testada. Crie um diretório isolado e restaure um arquivo simples. Esse procedimento não altera o /etc original:
sudo install -d -m 700 /tmp/restore-test
sudo rsync -a /mnt/backup/rsync-snapshots/current/etc/hostname /tmp/restore-test/
sudo ls -l /tmp/restore-test/hostname
sudo diff -u /etc/hostname /tmp/restore-test/hostname
Se o arquivo não mudou desde o último snapshot, diff não imprimirá nada e retornará código zero:
echo $?
Saída esperada:
0
Verifique também a idade do snapshot, o marcador de conclusão e os erros recentes:
sudo find /mnt/backup/rsync-snapshots/current -maxdepth 1 -name .complete -mmin -1500 -print
sudo grep -Ei 'erro|error|failed|permission denied' /var/log/rsync-backup/backup.log | tail -n 20
sudo df -h /mnt/backup
Uma execução diária saudável deve mostrar o arquivo .complete com menos de 1.500 minutos. O grep pode não retornar linhas, o que é normal. Configure monitoramento para alertar quando o marcador ficar antigo, o log não registrar conclusão ou o volume ultrapassar 80% de uso.
Atenção: se decidir remover /tmp/restore-test, confira primeiro o caminho com sudo ls -la /tmp/restore-test. Depois execute sudo rm -rf --one-file-system /tmp/restore-test. Esse comando é destrutivo e deve permanecer restrito ao diretório temporário criado para o teste.
Troubleshooting
O destino não está montado
Se o log mostrar ERRO: /mnt/backup não está montado, confira a montagem e o arquivo /etc/fstab:
findmnt /mnt/backup
sudo mount -a
findmnt /mnt/backup
Se mount -a gerar erro, não force o backup. Corrija UUID, tipo de sistema de arquivos ou credenciais da montagem. Use lsblk -f para localizar o UUID correto.
O cron não executa o script
Consulte o serviço e os eventos recentes:
sudo systemctl status cron --no-pager
sudo journalctl -u cron --since '2 hours ago' --no-pager
sudo run-parts --test /etc/cron.d
Confirme proprietário root, permissão 644, nova linha no final e sintaxe com o campo de usuário. Execute manualmente o comando completo do cron para separar erros de agendamento de erros no script.
O rsync retorna erro de permissão
Erros como Permission denied normalmente indicam que o processo não foi executado como root ou que o destino possui restrições. Verifique:
sudo namei -l /mnt/backup/rsync-snapshots
sudo touch /mnt/backup/rsync-snapshots/.permission-test
sudo rm /mnt/backup/rsync-snapshots/.permission-test
Em NFS, o recurso root_squash pode impedir gravação como root. Ajuste as permissões no servidor NFS ou use um destino projetado para receber o backup, sem desativar proteções às cegas.
O backup ocupa espaço demais
Veja o consumo por snapshot e a quantidade de arquivos com múltiplos links:
sudo du -sh /mnt/backup/rsync-snapshots/*
sudo find /mnt/backup/rsync-snapshots/current -xdev -type f -links +1 | head
Se não houver arquivos com mais de um link, confirme que current aponta para um snapshot válido e que o sistema de arquivos suporta hard links. Arquivos alterados diariamente, bancos e logs grandes consomem espaço novo em cada execução.
O processo fica preso ou executa duas vezes
Confira o bloqueio e os processos ativos:
sudo flock -n /run/lock/rsync-backup.lock true; echo $?
pgrep -a rsync
Código 1 no primeiro comando indica que outro processo mantém o bloqueio. Não apague o arquivo de lock como primeira tentativa. Identifique o PID, consulte o log e confirme se a cópia ainda progride antes de encerrar qualquer processo.
Próximos passos
Depois que o backup diário estiver estável, copie os snapshots para outro servidor ou armazenamento de objetos. A regra 3-2-1 recomenda três cópias dos dados, em dois tipos de mídia, com uma cópia fora do ambiente principal.
Adicione dumps consistentes de bancos antes do rsync, criptografe o destino externo e monitore falhas. Configure rotação para /var/log/rsync-backup/backup.log, alertas de espaço e verificação periódica de integridade. Faça uma restauração completa em uma VPS de testes pelo menos uma vez por trimestre.
Se os dados forem críticos, defina objetivos de recuperação. O RPO determina quanto dado você aceita perder entre backups. O RTO define quanto tempo a restauração pode levar. Ajuste a frequência, retenção e arquitetura conforme esses limites, em vez de depender apenas de uma execução diária.
Perguntas frequentes
O rsync cria um backup completo ou incremental?
Neste guia, cada diretório datado funciona como um snapshot completo para restauração, mas arquivos inalterados são armazenados como hard links para o snapshot anterior. Isso reduz o espaço utilizado sem exigir uma cadeia incremental durante a recuperação. Um arquivo modificado recebe novos dados no snapshot mais recente, enquanto a versão antiga permanece acessível no snapshot anterior. Como os hard links dependem do mesmo sistema de arquivos, o diretório de snapshots não pode ser dividido entre volumes diferentes. Você também não deve editar arquivos diretamente dentro dos snapshots, pois versões iguais podem compartilhar o mesmo inode.
Posso usar o rsync para fazer backup de MySQL ou PostgreSQL?
Você pode copiar os arquivos, mas isso não garante um backup transacional consistente enquanto o banco está em execução. Para MySQL ou MariaDB, gere um dump com `mysqldump` ou use uma ferramenta física compatível, como Mariabackup. Para PostgreSQL, use `pg_dump`, `pg_dumpall` ou uma estratégia baseada em `pg_basebackup` e WAL. Salve o resultado em um diretório incluído pelo rsync. Outra alternativa é criar um snapshot consistente do volume após coordenar o estado do banco. Sempre valide o dump restaurando-o em uma instância de teste, pois a existência do arquivo não comprova sua integridade.
Por que o backup deve ficar em um volume separado?
Uma pasta no mesmo disco protege contra exclusão acidental e algumas alterações indevidas, mas não protege contra falha do dispositivo, corrupção ampla do sistema de arquivos ou perda da VPS. Um volume separado reduz parte desse risco e evita que o crescimento dos snapshots ocupe todo o espaço da partição raiz. Ainda assim, um volume no mesmo provedor ou servidor pode ser afetado por incidentes maiores. Mantenha também uma cópia externa, preferencialmente criptografada e com credenciais diferentes. Confirme a montagem antes de cada execução para impedir que os dados sejam gravados acidentalmente no disco principal.
Como alterar a quantidade de snapshots mantidos?
Edite `/usr/local/sbin/backup-rsync` e mude a variável `RETENTION=7` para a quantidade desejada. Antes da alteração, copie o script e confira o espaço disponível com `df -h /mnt/backup`. Depois, execute `sudo bash -n /usr/local/sbin/backup-rsync` para validar a sintaxe. A remoção dos snapshots excedentes ocorre somente após uma cópia concluída. Aumentar a retenção eleva o consumo de espaço conforme a taxa de mudança dos arquivos, não necessariamente conforme o tamanho total da origem. Monitore o volume durante alguns ciclos antes de definir uma retenção longa.
Como enviar o backup para outra VPS com segurança?
Use rsync sobre SSH com uma chave dedicada, usuário restrito e destino exclusivo. Gere a chave sem reutilizar a credencial administrativa, instale a chave pública no servidor de backup e valide a impressão digital do host. Restrinja o usuário remoto por permissões, firewall e, quando possível, opções em `authorized_keys`. Teste primeiro com `rsync --dry-run`. Para preservar proprietários, ACLs e atributos estendidos, o usuário remoto precisa das permissões adequadas, ou você deve aceitar uma restauração com metadados limitados. Mantenha o servidor receptor isolado para reduzir o risco de um invasor apagar simultaneamente origem e cópias.
Como saber se o cron executou o backup corretamente?
Confira três sinais: uma linha recente de conclusão no log, um diretório datado novo e o arquivo `.complete` dentro do snapshot atual. Use `sudo tail -n 30 /var/log/rsync-backup/backup.log`, `sudo readlink -f /mnt/backup/rsync-snapshots/current` e `sudo stat /mnt/backup/rsync-snapshots/current/.complete`. Consulte também `journalctl -u cron` para confirmar que o agendador iniciou a tarefa. O teste mais confiável continua sendo restaurar arquivos periodicamente. Configure um alerta quando `.complete` ultrapassar a idade esperada ou quando o volume de destino ficar próximo da capacidade.
Fontes consultadas
- Documentação oficial do rsync · coletado em 28/09/2026
- Manual oficial do cron no Ubuntu · coletado em 28/09/2026
- Manual oficial do crontab no Ubuntu · coletado em 28/09/2026
- Documentação oficial do flock · coletado em 28/09/2026