Saltar para o conteúdo principal
data-recovery-headINFO

Backup automatizado com cron e rsync em 2026: guia Linux completo

Automatize backups Linux com cron e rsync em 2026: sintaxe cron completa, scripts shell robustos com registo e alertas, rsnapshot, BorgBackup e monitorização com Healthchecks.io. Receitas cron + rsync testadas em campo para copiar.

Por Eric Gerard · Éditeur · Save My Disk14 min de leituraFoto via Unsplash

Uma rotação cron mal configurada que sobrescreve os arquivos em vez de os incrementar é uma das formas clássicas de perder semanas de registos do servidor sem dar conta. Automatizar corretamente os backups Linux com cron e rsync evita precisamente essa classe de erros. Este guia documenta uma configuração cron + rsync testada em campo para 2026, armadilhas comuns incluídas.

A premissa é simples: a automação não é opcional nos backups. Os humanos esquecem-se. O cron não. Um bom sistema automatizado corre todas as noites às 02:00 sem que ninguém pense nisso — e é exatamente então que compensa, no dia em que uma base de dados fica corrompida ou alguém apaga sem querer uma grande diretoria de arquivos.

Porquê automatizar os backups

A resposta curta: porque a memória humana é um péssimo agendador para tarefas recorrentes críticas.

Os humanos esquecem-se, os scripts não. O inquérito anual de 2024 da Backblaze sobre hábitos de backup revela que 67% dos utilizadores que afirmam «fazer backup regularmente» fazem-no na realidade de forma irregular — com intervalos de 2 a 6 semanas entre backups. A regularidade percebida é sistematicamente superior à real. Uma tarefa cron diária às 02:00 corre sem exceção: durante as férias, fins de semana, noites com flutuações de energia (se o servidor tiver uma UPS).

O backup incremental torna a automação prática. Sem o rsync e as suas transferências delta, fazer backup de 500 GB de dados todas as noites seria proibitivo (50 a 100 GB de transferência de rede para uma diretoria de fotos padrão). Com o rsync, apenas os bytes alterados desde o último backup são transferidos. Para um backup noturno típico para um NAS em LAN, a cópia completa inicial pode demorar algumas horas, mas cada execução seguinte costuma concluir-se em minutos porque só os blocos alterados passam pelo cabo.

Escalar para várias máquinas. Passar de um para vários servidores torna o backup manual um procedimento longo que nunca é feito corretamente. Um script cron centralizado que recolhe os backups de todas as máquinas para um único destino exige zero tempo humano.

A monitorização automática deteta falhas. Um backup que falha em silêncio há 3 semanas é mais perigoso do que um backup nunca configurado — pelo menos aí sabe que não existe. Com um ping ao Healthchecks.io no fim do script, recebe um e-mail no momento em que um backup falha ou não corre como previsto.

rsync em 2026: sintaxe e opções essenciais

O rsync é uma ferramenta de sincronização incremental de ficheiros desenvolvida por Andrew Tridgell em 1996. O seu algoritmo de transferência delta transfere apenas os blocos modificados de um ficheiro em vez do ficheiro completo — é este o fundamento da sua eficiência nos backups diários.

Sintaxe básica:

rsync -avz --delete SOURCE DESTINATION

Opções explicadas:

  • -a (archive): preserva permissões, timestamps, symlinks, dono, grupo. Equivale a -rlptgoD.
  • -v (verbose): mostra os ficheiros transferidos.
  • -z (compress): ativa a compressão durante a transferência. Útil em WAN, inútil em LAN Gigabit.
  • --delete: remove do destino os ficheiros que já não existem na origem.

Backup local para NAS:

rsync -av --delete /home/eric/ /mnt/nas/backup/eric-home/

Backup para servidor remoto via SSH:

rsync -avz --delete -e "ssh -i /home/eric/.ssh/backup_key -p 22" \
  /var/www/ \
  backup@192.168.1.100:/data/backups/www/

Opções avançadas em 2026:

# --mkpath: create destination directories if absent (recent flag, rsync 3.2.3+)
rsync -av --mkpath /source/ user@host:/path/that/does/not/exist/

# --exclude: skip specific patterns
rsync -av --exclude='*.log' --exclude='tmp/' --exclude='.git/' /source/ /dest/

# --bwlimit: cap bandwidth (in KB/s)
rsync -av --bwlimit=20000 /source/ user@host:/dest/

# --checksum: force hash-based verification (slower but more reliable)
rsync -avc --checksum /source/ /dest/

# Dry run: simulate without changing anything
rsync -avn --delete /source/ /dest/

Exemplo completo: backup de um VPS para uma Hetzner Storage Box:

rsync -avz --delete \
  --exclude='*.sock' \
  --exclude='/proc' \
  --exclude='/sys' \
  --exclude='/dev' \
  --exclude='/run' \
  --bwlimit=30000 \
  -e "ssh -i /root/.ssh/hetzner_backup -p 23" \
  /etc/ /home/ /var/www/ /var/backups/ \
  u123456@u123456.your-storagebox.de:/backups/vps-main/

Um script como este, agendado para a noite, costuma transferir apenas os dados alterados para um destino remoto como uma Hetzner Storage Box (preço 2026: 3,81 €/mês por 100 GB).

Cron: sintaxe completa e exemplos práticos

O cron é o agendador de tarefas padrão do Unix, presente em todas as distribuições Linux. O comando crontab -e edita a tabela cron do utilizador atual.

A sintaxe de cinco campos:

# ┌───── minute (0 - 59)
# │ ┌───── hour (0 - 23)
# │ │ ┌───── day of month (1 - 31)
# │ │ │ ┌───── month (1 - 12)
# │ │ │ │ ┌───── day of week (0 - 7, 0 and 7 = Sunday)
# │ │ │ │ │
# * * * * * command

Exemplos de agendamento comuns:

# Every minute (testing / monitoring)
* * * * * /usr/local/bin/monitor.sh

# Every hour at H:00
0 * * * * /usr/local/bin/hourly-backup.sh

# Every day at 02:00
0 2 * * * /usr/local/bin/daily-backup.sh

# Every Sunday at 03:00
0 3 * * 0 /usr/local/bin/weekly-backup.sh

# 1st of every month at 04:00
0 4 1 * * /usr/local/bin/monthly-backup.sh

# Every 6 hours
0 */6 * * * /usr/local/bin/incremental.sh

# Weekdays (Mon-Fri) at 08:30
30 8 * * 1-5 /usr/local/bin/workday-sync.sh

Variáveis de ambiente importantes na crontab:

# cron does not inherit user PATH — always define it explicitly
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=admin@mydomain.com

# Explicit timezone (avoids scheduling surprises)
CRON_TZ=America/New_York

0 2 * * * /usr/local/bin/daily-backup.sh >> /var/log/backup.log 2>&1

systemd-timers: a alternativa moderna

Em sistemas com systemd (Ubuntu 16.04+, Debian 9+, CentOS 7+), os timers systemd oferecem melhor rastreabilidade:

# /etc/systemd/system/backup-daily.timer
[Unit]
Description=Daily rsync backup

[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true  # Catches up missed jobs if server was off
Unit=backup-daily.service

[Install]
WantedBy=timers.target
# /etc/systemd/system/backup-daily.service
[Unit]
Description=Daily rsync backup
After=network.target

[Service]
Type=oneshot
User=root
ExecStart=/usr/local/bin/daily-backup.sh
Nice=19
IOSchedulingClass=idle
# Activation
systemctl enable backup-daily.timer
systemctl start backup-daily.timer
systemctl list-timers  # Check status
journalctl -u backup-daily.service  # View logs

A vantagem chave de Persistent=true: se o servidor estava desligado às 02:00, a tarefa corre no arranque seguinte. O cron padrão falha as tarefas se a máquina estiver offline.

Script de backup completo: registo, tratamento de erros, alertas

Filas de servidores num centro de dados
Filas de servidores num centro de dados

Eis um script de referência pronto para produção que pode adaptar. Cobre registo estruturado, tratamento de erros e notificações.

#!/bin/bash
# /usr/local/bin/daily-backup.sh
# Daily rsync backup with logging and alerts

set -euo pipefail

# ── Configuration ──────────────────────────────────────────────────────────────
BACKUP_SOURCE="/home /etc /var/www /var/backups"
BACKUP_DEST="/mnt/nas/backups/vps-main"
LOG_FILE="/var/log/backup-daily.log"
MAX_LOG_SIZE_MB=50
LOCK_FILE="/tmp/backup-daily.lock"
HEALTHCHECK_URL="https://hc-ping.com/YOUR-UUID-HERE"  # Healthchecks.io
NOTIFY_EMAIL="admin@mydomain.com"
RSYNC_OPTIONS="-avz --delete --delete-after --exclude='*.sock' --exclude='*.pid'"
SSH_KEY="/root/.ssh/backup_key"
REMOTE_HOST="backup@192.168.1.100"
REMOTE_PATH="/data/backups"
BWLIMIT=30000  # KB/s — 30 MB/s cap

# ── Functions ──────────────────────────────────────────────────────────────────
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}

send_alert() {
    local subject="$1"
    local body="$2"
    echo "$body" | mail -s "$subject" "$NOTIFY_EMAIL" 2>/dev/null || true
    # Healthchecks.io: ping /fail to signal failure
    curl -fsS --retry 3 --max-time 10 "${HEALTHCHECK_URL}/fail" \
        --data-raw "$body" > /dev/null 2>&1 || true
}

rotate_log() {
    local size_mb
    size_mb=$(du -sm "$LOG_FILE" 2>/dev/null | cut -f1 || echo 0)
    if [ "$size_mb" -gt "$MAX_LOG_SIZE_MB" ]; then
        mv "$LOG_FILE" "${LOG_FILE}.$(date +%Y%m%d)"
        gzip "${LOG_FILE}.$(date +%Y%m%d)" 2>/dev/null || true
        log "Log rotated (size threshold exceeded)"
    fi
}

cleanup() {
    rm -f "$LOCK_FILE"
}

# ── Preliminary checks ─────────────────────────────────────────────────────────
# Lock: prevent parallel executions
if [ -f "$LOCK_FILE" ]; then
    log "ERROR: backup already running (lockfile present). Aborting."
    send_alert "[BACKUP] Lock conflict on $(hostname)" \
        "Backup was already running. Check PID in $LOCK_FILE."
    exit 1
fi

trap cleanup EXIT
echo $$ > "$LOCK_FILE"

rotate_log
log "═══ Starting daily backup ═══"

# Check destination connectivity
if ! ssh -i "$SSH_KEY" -o ConnectTimeout=10 -o BatchMode=yes \
    "$REMOTE_HOST" "echo OK" > /dev/null 2>&1; then
    log "ERROR: cannot reach $REMOTE_HOST"
    send_alert "[BACKUP] Destination unreachable on $(hostname)" \
        "SSH to $REMOTE_HOST failed. Check network/key."
    exit 2
fi

# ── rsync execution ────────────────────────────────────────────────────────────
ERRORS=0
START_TIME=$(date +%s)

for SOURCE_DIR in $BACKUP_SOURCE; do
    if [ ! -d "$SOURCE_DIR" ]; then
        log "WARNING: source directory absent: $SOURCE_DIR"
        continue
    fi

    DEST_DIR="${REMOTE_PATH}/$(basename "$SOURCE_DIR")"
    log "Syncing: $SOURCE_DIR → $REMOTE_HOST:$DEST_DIR"

    if rsync $RSYNC_OPTIONS \
        --bwlimit="$BWLIMIT" \
        -e "ssh -i $SSH_KEY -o BatchMode=yes" \
        "$SOURCE_DIR/" \
        "$REMOTE_HOST:$DEST_DIR/" \
        >> "$LOG_FILE" 2>&1; then
        log "OK: $SOURCE_DIR synced"
    else
        log "ERROR: rsync failed for $SOURCE_DIR (exit code: $?)"
        ERRORS=$((ERRORS + 1))
    fi
done

# ── Final result ───────────────────────────────────────────────────────────────
END_TIME=$(date +%s)
DURATION=$((END_TIME - START_TIME))
DURATION_MIN=$((DURATION / 60))

if [ "$ERRORS" -eq 0 ]; then
    log "Backup completed successfully in ${DURATION_MIN} min"
    # Healthchecks.io success ping
    curl -fsS --retry 3 --max-time 10 "$HEALTHCHECK_URL" > /dev/null 2>&1 || true
else
    log "Backup completed with $ERRORS error(s) in ${DURATION_MIN} min"
    send_alert "[BACKUP] $ERRORS error(s) on $(hostname)" \
        "Backup finished with $ERRORS error(s). Duration: ${DURATION_MIN} min. See $LOG_FILE."
fi

log "═══ Backup complete ═══"

Adicionar à crontab:

SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
0 2 * * * /usr/local/bin/daily-backup.sh

Como o rsync transfere apenas o que mudou, um backup incremental de algumas centenas de GB costuma demorar apenas alguns minutos por noite assim que a sincronização inicial estiver concluída.

rsnapshot: rotação automática de snapshots

O rsnapshot é um wrapper do rsync que implementa automaticamente a rotação de snapshots com hard links — cada snapshot parece uma cópia completa mas só guarda os ficheiros realmente novos ou modificados.

Instalação:

apt install rsnapshot  # Debian/Ubuntu
yum install rsnapshot  # CentOS/RHEL

Configuração /etc/rsnapshot.conf (excerto):

# IMPORTANT: tabs required between fields (not spaces)
config_version  1.2

# Snapshot root directory
snapshot_root   /mnt/nas/rsnapshot/

# rsync command
cmd_rsync       /usr/bin/rsync

# Rotation intervals
retain  hourly  6    # 6 hourly snapshots
retain  daily   7    # 7 days
retain  weekly  4    # 4 weeks
retain  monthly 12   # 12 months

# Global rsync options
rsync_short_args    -az
rsync_long_args     --delete --delete-excluded --numeric-ids

# Sources to back up
backup  /home/eric/          localhost/
backup  /etc/                localhost/
backup  /var/www/            localhost/
backup  root@192.168.1.10:/home/  web-server/
backup  root@192.168.1.10:/etc/   web-server/

# Exclusions
exclude *.log
exclude tmp/
exclude .cache/

crontab do rsnapshot:

# Hourly snapshots (6am - 10pm)
0 6-22 * * *    /usr/bin/rsnapshot hourly

# Daily at 02:30
30 2 * * *      /usr/bin/rsnapshot daily

# Weekly on Monday at 03:00
0 3 * * 1       /usr/bin/rsnapshot weekly

# Monthly on 1st at 04:00
0 4 1 * *       /usr/bin/rsnapshot monthly

Estrutura de diretorias resultante:

/mnt/nas/rsnapshot/
├── daily.0/       ← yesterday
│   ├── localhost/
│   │   ├── home/eric/
│   │   ├── etc/
│   │   └── var/www/
│   └── web-server/
├── daily.1/       ← two days ago
├── daily.2/
...
├── weekly.0/      ← last week
├── monthly.0/     ← last month

O restauro é trivial: cp -a /mnt/nas/rsnapshot/daily.2/localhost/home/eric/file.txt /home/eric/. Sem ferramenta especial, apenas uma cópia a partir de uma diretoria de snapshot.

Espaço em disco: com 180 GB de dados de origem e uma rotação de 7 diários + 4 semanais + 12 mensais = 23 snapshots, uso cerca de 320 GB no NAS (160 GB de dados «duplicados», porque os ficheiros inalterados partilham hard links entre snapshots).

BorgBackup: deduplicação e cifragem para backups sensíveis

O rsync destaca-se na sincronização de ficheiros. O BorgBackup é superior quando precisa de deduplicação ao nível do bloco, cifragem nativa e compressão variável. É a minha ferramenta para backups fora do local para uma Hetzner Storage Box e para backups que contêm dados pessoais.

Comparação rsync vs BorgBackup:

CritériorsyncBorgBackup
DeduplicaçãoNão (hard links via rsnapshot)Sim (blocos variáveis ~512 KB)
Cifragem em repousoNãoAES-256 nativa
CompressãoDurante a transferência (-z)LZ4/ZSTD/ZLIB integrada
Restauro de um único ficheiroSimples (cp a partir do snapshot)borg extract
Espaço em discoMaior (sem dedup real)40-60% menor em dados mistos
Complexidade de configuraçãoBaixaModerada

Instalação e inicialização:

apt install borgbackup  # Ubuntu 22.04: version 1.2.x

# Initialize an encrypted repository (recommended mode)
borg init --encryption=repokey-blake2 user@nas:/data/borg-repo/

# Store the passphrase in a password manager
# AND in a secure file outside the machine being backed up

Script de backup Borg com política de prune:

#!/bin/bash
export BORG_PASSPHRASE="YOUR_LONG_AND_COMPLEX_PASSPHRASE"
export BORG_REPO="user@nas:/data/borg-repo"

# Create snapshot with timestamp
borg create \
    --verbose \
    --compression lz4 \
    --exclude-caches \
    --exclude '/home/*/.cache' \
    --exclude '/home/*/.local/share/Trash' \
    "${BORG_REPO}::$(hostname)-$(date +%Y%m%d-%H%M%S)" \
    /home /etc /var/www

# Retention policy: 7 daily + 4 weekly + 12 monthly
borg prune \
    --verbose \
    --list \
    --keep-daily=7 \
    --keep-weekly=4 \
    --keep-monthly=12 \
    "${BORG_REPO}"

# Integrity verification (recommended weekly)
# borg check "${BORG_REPO}"

Restauro:

# List archives
borg list "${BORG_REPO}"

# Restore a specific file
borg extract "${BORG_REPO}::server-20260608-020000" home/eric/documents/important.pdf

# Full restoration
borg extract "${BORG_REPO}::server-20260608-020000"

Quando preferir o Borg ao rsync:

  • Dados sensíveis (documentos pessoais, bases de dados que contêm dados pessoais)
  • Backups para armazenamento na nuvem ou hosts não fiáveis
  • Volumes de dados com elevada redundância (fotos, código-fonte com histórico git)
  • Necessidade de um histórico de snapshots comprimido em armazenamento limitado

Num destino remoto de 100 GB como uma Hetzner Storage Box, o Borg pode manter vários meses de snapshots deduplicados e comprimidos numa fração do espaço que as cópias rsync simples exigiriam para a mesma profundidade de histórico — tipicamente um rácio de compressão bastante abaixo de 1, consoante o grau de redundância dos dados de origem.

Monitorização e alertas: nunca assumir que o backup está a correr

Um backup que falha em silêncio há 3 semanas é um desastre à espera de acontecer. A monitorização não é opcional.

Healthchecks.io: a abordagem mais simples

O Healthchecks.io é um serviço de monitorização de cron baseado em pings. Crie uma verificação com o intervalo esperado (diário 24h + 1h de tolerância), adicione o ping no fim do seu script. Se o ping não chegar, recebe um e-mail.

# At the end of the backup script, on success:
curl -fsS --retry 3 --max-time 10 \
    "https://hc-ping.com/YOUR-UUID" > /dev/null 2>&1 || true

# On failure, ping the /fail endpoint:
curl -fsS --retry 3 --max-time 10 \
    "https://hc-ping.com/YOUR-UUID/fail" > /dev/null 2>&1 || true

Plano gratuito: 20 verificações. Suficiente para 4 servidores com monitorização diária + semanal. Plano Business a 20 $/ano para equipas.

Monitorização de registos com um simples grep:

# Crontab: check backup logs for errors every hour
0 * * * * grep -i "error\|fail" /var/log/backup-daily.log \
    | tail -5 \
    | mail -s "[$(hostname)] Backup errors" admin@mydomain.com 2>/dev/null || true

Script de verificação da atualidade do backup:

#!/bin/bash
# Verify that the most recent backup is less than 26 hours old
BACKUP_DIR="/mnt/nas/backups"
MAX_AGE_HOURS=26

find "$BACKUP_DIR" -name "*.log" -newer \
    <(date -d "$MAX_AGE_HOURS hours ago") > /tmp/recent_backups 2>/dev/null

if [ ! -s /tmp/recent_backups ]; then
    echo "ALERT: No recent backup on $(hostname)" \
    | mail -s "[BACKUP] Backup too old!" admin@mydomain.com
fi

Prometheus + Grafana para homelabs avançados:

Para ambientes com vários servidores, o node_exporter do Prometheus expõe métricas do sistema de ficheiros. Uma regra do Alertmanager pode disparar uma notificação no Slack se o timestamp do último backup ultrapassar um limiar:

# prometheus/rules/backup.yml
groups:
  - name: backup_freshness
    rules:
      - alert: BackupStaleness
        expr: |
          (time() - node_filesystem_file_content_mtime_seconds{
            mountpoint="/mnt/nas",
            path="/data/backups/vps-main"
          }) > 90000
        for: 1h
        labels:
          severity: warning
        annotations:
          summary: "Stale backup on {{ $labels.instance }}"
          description: "Last backup {{ $value | humanizeDuration }} ago"

Um painel como este pode correr em hardware tão modesto como um Raspberry Pi, dando-lhe monitorização central para vários servidores a um custo de infraestrutura quase nulo (o Prometheus e o Grafana são ambos open source).


A automação cron + rsync é a camada técnica que torna prática à escala a estratégia de backup 3-2-1. Para perceber como isto encaixa numa arquitetura de backup completa, consulte o guia da estratégia de backup 3-2-1. Para utilizadores de Windows e Mac que gerem servidores Linux a par de máquinas de secretária, o guia de backup automático Windows e Mac cobre os equivalentes com interface gráfica.

Quando a prevenção falha e a recuperação de dados se torna necessária, o guia de recuperação de dados de disco rígido 2026 cobre as opções caseiras e profissionais, e a comparação dos melhores softwares de recuperação de dados 2026 avalia as ferramentas disponíveis. Para estimativas de custos de recuperação profissional, consulte o nosso guia de custos de recuperação de dados 2026.

Escolha editorial
4.5 / 5

Backup com interface gráfica automatizado para Windows e Mac

Se também gere máquinas Windows/Mac a par dos seus servidores Linux — o EaseUS Todo Backup automatiza os backups sem qualquer linha de comandos · Versão gratuita disponível

Fundada em 2004Garantia de 30 diasVersão gratuita de 2 GB
Ver a oferta
Escolha editorial
4.5 / 5

Recover your deleted files → EaseUS

Free scan · deleted, formatted & lost files · Windows & Mac

Fundada em 2004Garantia de 30 diasVersão gratuita de 2 GB
Ver a oferta