Ir al contenido

Automatizar backups incrementales de Docker con restic hacia S3

Rogelio Guerra Riverón
Autor
Rogelio Guerra Riverón
Construyendo mi propia infraestructura web desde cero. Aquí documento cada paso: servidores, redes, contenedores y lo que vaya surgiendo.

El problema
#

Tenía PostgreSQL y Grafana corriendo en Docker con volúmenes persistentes. La idea de perder esos datos me mantenía despierto. Backups manuales no son confiables. Necesitaba algo automático, eficiente y verificable.

Después de probar varias opciones, me decidí por restic + S3 + cron jobs. Es directo y funciona.

Por qué restic
#

Restic hace backups incrementales deduplicados. Solo envía lo que cambió. Es perfecto para volúmenes Docker que típicamente tienen pequeños cambios día a día. Además verifica integridad automáticamente.

Setup básico
#

1. Instalar restic
#

sudo apt-get update
sudo apt-get install restic

2. Crear credenciales S3
#

Necesitas acceso a un bucket S3 (o MinIO si usas self-hosted). Crea las credenciales con permisos limitados:

export AWS_ACCESS_KEY_ID="tu_access_key"
export AWS_SECRET_ACCESS_KEY="tu_secret_key"
export AWS_DEFAULT_REGION="us-east-1"

Guarda esto en un archivo seguro (/root/.restic-env):

export AWS_ACCESS_KEY_ID="..."
export AWS_SECRET_ACCESS_KEY="..."
export RESTIC_REPOSITORY="s3:https://s3.amazonaws.com/tu-bucket/backups"
export RESTIC_PASSWORD="tu_password_restic_fuerte"

Permisos: chmod 600 /root/.restic-env

3. Inicializar el repositorio
#

source /root/.restic-env
restic init

Script de backup
#

Crea /opt/backup-docker.sh:

#!/bin/bash

source /root/.restic-env

BACKUP_DIRS=(
  "/var/lib/docker/volumes/postgres_data/_data"
  "/var/lib/docker/volumes/grafana_data/_data"
)

TIMESTAMP=$(date +%Y-%m-%d_%H:%M:%S)
LOG_FILE="/var/log/restic-backup.log"

echo "=== Backup iniciado: $TIMESTAMP ===" >> $LOG_FILE

for dir in "${BACKUP_DIRS[@]}"; do
  if [ -d "$dir" ]; then
    echo "Backupeando: $dir" >> $LOG_FILE
    restic backup "$dir" --tag "docker" --tag "$(date +%A)" >> $LOG_FILE 2>&1
    
    if [ $? -eq 0 ]; then
      echo "✓ Backup exitoso: $dir" >> $LOG_FILE
    else
      echo "✗ Error en backup: $dir" >> $LOG_FILE
      # Aquí podrías enviar una notificación
    fi
  fi
done

echo "=== Backup completado ===" >> $LOG_FILE

Permisos:

chmod +x /opt/backup-docker.sh

Automatizar con cron
#

Edita la crontab:

crontab -e

Agrega:

# Backup diario a las 2 AM
0 2 * * * /opt/backup-docker.sh

# Verificación de integridad cada domingo a las 3 AM
0 3 * * 0 source /root/.restic-env && restic check --with-cache >> /var/log/restic-check.log 2>&1

# Limpieza de snapshots viejos cada mes
0 4 1 * * source /root/.restic-env && restic forget --keep-daily 30 --keep-weekly 12 --prune >> /var/log/restic-prune.log 2>&1

Validación programada
#

La línea de restic check verifica que todos los datos estén íntegros. Es lo que duermes más tranquilo:

source /root/.restic-env
restic check --with-cache

Si hay corrupción, lo sabrás. Si todo está bien, ves esto:

using backend repository stored in s3:...
checking integrity of repository
[...] 100.00%  checking snapshots, keys, buckets
check successful, no errors were found

Restaurar
#

Cuando lo necesites (espero que no):

source /root/.restic-env
restic restore latest --target /tmp/restore

O un snapshot específico:

restic snapshots  # lista todos
restic restore <snapshot-id> --target /tmp/restore

En producción
#

Monitorea los logs:

tail -f /var/log/restic-backup.log

Considera agregar alertas si los backups fallan. Yo tengo un script que envía notificación a Discord si detecta errores.

Resultados
#

Después de tres meses:

  • PostgreSQL: 2.3 GB comprimido
  • Grafana: 150 MB comprimido
  • Almacenamiento total en S3: 1.8 GB (deduplicación en acción)

Los backups incrementales tardan entre 30 segundos y 2 minutos. Las verificaciones de integridad unos 5 minutos.

Es confiable. Dormimos mejor.


Actualizado: 2026-06-10