Estratégia de backup para VPS

Backup não é apenas fazer uma cópia, é ter um plano testado para restaurar em tempo hábil quando algo dá errado. Uma VPS em produção precisa de estratégia de backup para banco de dados, arquivos de upload, configurações e certificados. A regra 3-2-1 (3 cópias, 2 mídias, 1 offsite) é o ponto de partida.

O que fazer backup na VPS

Mapeie todos os dados que precisam de backup antes de definir a estratégia:

bash
# Checklist de o que fazer backup:

# 1. Banco de dados (mais crítico)
# ├── PostgreSQL: pg_dump de cada banco
# ├── MySQL/MariaDB: mysqldump
# ├── Redis: dump.rdb (se persistência habilitada)
# └── SQLite: cópia do arquivo .db

# 2. Arquivos de upload dos usuários
# ├── /var/www/uploads/ (imagens, documentos)
# └── /opt/app/storage/ (arquivos da aplicação)

# 3. Configurações e secrets
# ├── /etc/nginx/ (config do web server)
# ├── /etc/letsencrypt/ (certificados SSL)
# ├── /opt/app/.env (variáveis de ambiente)
# └── /etc/cron.d/ (crontabs customizados)

# 4. Dados de serviços self-hosted
# ├── /var/lib/docker/volumes/ (volumes Docker)
# └── Configurações de apps (Grafana, n8n, etc.)

# O que NÃO precisa de backup:
# ✗ Código fonte (está no Git)
# ✗ node_modules, .venv (regeneráveis)
# ✗ Logs antigos (arquivar separadamente se necessário)
# ✗ Arquivos temporários e cache

Script de backup completo da VPS

Script que faz backup de banco + arquivos + configurações:

bash
#!/bin/bash
# /opt/scripts/backup-full.sh
set -euo pipefail

BACKUP_DIR="/var/backups/vps"
DATE=$(date +%Y%m%d_%H%M)
RETENTION_DAYS=7
LOG="/var/log/backup-full.log"
exec >> "$LOG" 2>&1

echo "=== Backup completo: $(date) ==="
mkdir -p "$BACKUP_DIR"

# 1. Banco de dados PostgreSQL
echo "--- PostgreSQL ---"
PGPASSWORD="$DB_PASSWORD" pg_dump -U minha_app minha_db \
  | gzip > "$BACKUP_DIR/postgres_${DATE}.sql.gz"

# 2. Arquivos de upload
echo "--- Uploads ---"
tar -czf "$BACKUP_DIR/uploads_${DATE}.tar.gz" \
  --exclude='*.tmp' \
  /var/www/uploads/ 2>/dev/null || true

# 3. Configurações
echo "--- Configs ---"
tar -czf "$BACKUP_DIR/configs_${DATE}.tar.gz" \
  /etc/nginx/ \
  /etc/letsencrypt/ \
  /opt/app/.env \
  /etc/cron.d/ 2>/dev/null || true

# 4. Upload para S3 (ou B2/Wasabi)
echo "--- Upload offsite ---"
aws s3 sync "$BACKUP_DIR" s3://meu-bucket/vps-backups/ \
  --exclude "*" \
  --include "*_${DATE}*" \
  --storage-class STANDARD_IA

# 5. Limpar backups locais antigos
find "$BACKUP_DIR" -mtime +$RETENTION_DAYS -delete

echo "=== Backup concluído: $(date) ==="

Backup incremental com restic

restic é uma ferramenta moderna de backup com deduplicação, compressão e criptografia:

bash
# Instalar restic
sudo apt install -y restic

# Inicializar repositório (S3 como backend):
export AWS_ACCESS_KEY_ID="sua_key"
export AWS_SECRET_ACCESS_KEY="sua_secret"
export RESTIC_REPOSITORY="s3:sa-east-1.amazonaws.com/meu-bucket/restic"
export RESTIC_PASSWORD="senha_de_criptografia_forte"

restic init

# Fazer backup de múltiplos diretórios:
restic backup \
  /var/www \
  /opt/app \
  /etc/nginx \
  /etc/letsencrypt \
  --exclude "/var/www/cache" \
  --exclude "*.log" \
  --tag "vps-producao"

# Listar snapshots:
restic snapshots

# Verificar integridade:
restic check

# Política de retenção automática:
restic forget \
  --keep-daily 7 \
  --keep-weekly 4 \
  --keep-monthly 12 \
  --prune

# Vantagens do restic:
# + Deduplicação: backup incremental real (apenas blocos novos)
# + Criptografia: AES-256 antes de enviar para o cloud
# + Verificação: hash de integridade de cada bloco

Definir RTO e RPO para cada componente

Recovery Time Objective e Recovery Point Objective guiam a estratégia:

bash
# RTO: quanto tempo tenho para restaurar?
# RPO: quanta perda de dados é aceitável?

# Exemplo de tabela de SLA para VPS de API:
#
# Componente          | RPO         | RTO    | Estratégia
# ─────────────────────────────────────────────────────────
# Banco PostgreSQL    | 1 hora      | 2 horas | pg_dump a cada hora + offsite
# Arquivos de upload  | 24 horas    | 4 horas | backup diário + S3
# Certificados SSL    | 7 dias      | 30 min  | Let's Encrypt auto-renova
# Configurações       | 7 dias      | 1 hora  | backup semanal + Git
# Código da aplicação | 0 (em Git)  | 30 min  | git clone + deploy

# Calcular custo de armazenamento:
# 10 GB de dados, backup diário por 30 dias:
# Sem dedup: 300 GB × $0.023/GB (S3 Standard) = $6.90/mês
# Com restic (dedup ~70%): ~90 GB × $0.0125/GB (S3 IA) = $1.13/mês

Rotina de teste de restore

Agende testes periódicos para confirmar que o backup está funcional:

bash
#!/bin/bash
# /opt/scripts/test-restore-weekly.sh
# Agendar: todo domingo às 5h
# 0 5 * * 0 /opt/scripts/test-restore-weekly.sh

set -euo pipefail
LOG="/var/log/restore-test.log"
exec >> "$LOG" 2>&1

echo "=== Teste de restore semanal: $(date) ==="

# 1. Baixar backup mais recente do S3
LATEST=$(aws s3 ls s3://meu-bucket/vps-backups/ \
  --recursive | grep postgres | sort | tail -1 | awk '{print $4}')
aws s3 cp "s3://meu-bucket/$LATEST" /tmp/test-backup.sql.gz

# 2. Testar restore do PostgreSQL
TEST_DB="restore_test_$(date +%s)"
sudo -u postgres createdb "$TEST_DB"
gunzip -c /tmp/test-backup.sql.gz | sudo -u postgres psql "$TEST_DB" > /dev/null

# 3. Validar integridade
ROWS=$(sudo -u postgres psql -d "$TEST_DB" -t -c "SELECT count(*) FROM usuarios")
echo "Linhas na tabela usuarios: $ROWS"
[ "$ROWS" -gt 0 ] || (echo "FALHA: tabela vazia!" && exit 1)

# 4. Limpar
sudo -u postgres dropdb "$TEST_DB"
rm /tmp/test-backup.sql.gz

echo "=== Teste concluído com sucesso: $(date) ==="

Não quer configurar manualmente?

Implante o VPS em menos de 5 minutos com a Runstack. Infraestrutura da OPEN Datacenter, com servidores em São Paulo.

Perguntas frequentes

3 cópias dos dados: original + 2 backups. 2 tipos diferentes de mídia: ex: disco local + cloud storage. 1 cópia offsite: em localização geográfica diferente. Na prática para VPS: dados na VPS (1 cópia) + backup local em /var/backups (2ª cópia) + upload para S3/B2 (3ª cópia, offsite). O S3 é a cópia mais importante, a VPS pode ser destruída completamente.

Não completamente. Snapshot de VPS (quando disponível no provedor): backup completo do disco, rápido de restaurar, mas pode conter banco em estado inconsistente se o snapshot ocorrer no meio de uma transação. pg_dump sempre garante consistência. Use ambos: snapshot para disaster recovery rápido + pg_dump para restaurações cirúrgicas.

Backblaze B2: $0.006/GB/mês (mais barato). AWS S3 Standard-IA: $0.0125/GB/mês. Wasabi: $0.0069/GB/mês sem taxas de egress. Para 50 GB de backups: B2 custa $0.30/mês, S3 IA $0.63/mês. Com deduplicação e compressão (restic), os dados reais armazenados podem ser 30-70% menores.

Adicione ao script de backup: if [ $? -ne 0 ]; then curl -X POST "$TELEGRAM_WEBHOOK" -d "text=Backup falhou na VPS prod: $(date)"; fi. Ou use healthchecks.io (gratuito): o script de backup faz curl healthchecks.io/ping/UUID ao finalizar com sucesso, se o ping não chegar, o serviço envia alerta por email/Telegram.

Com backup completo e runbook documentado: provisionar VPS nova + instalar dependências (15-30 min) + restaurar banco (5-30 min dependendo do tamanho) + restaurar arquivos (10-60 min) + atualizar DNS (0-48h para propagação) = 1-3h de RTO realista. Documente o processo de restore e execute um drill completo anualmente.