Script de Rotación de Backups en Bash
Backups automatizados con políticas de retención usando bash y find.
Nota para desarrolladores hispanohablantes: Esta guía incluye ejemplos y convenciones de nomenclatura adaptadas a equipos que trabajan en español. Cuando existen diferencias significativas en terminología técnica entre el inglés y el español, se indican explícitamente para facilitar la comunicación en equipos multiculturales.
Visión General
La rotación de backups mantiene una cantidad fija de backups y borra los viejos automáticamente. Este script usa tar para compresión y find para limpieza. Soporta políticas de retención diaria, semanal y mensual para que siempre tengas backups recientes e históricos sin llenar el disco.
Cuándo Usar
- Necesitas backups automatizados para una web app o base de datos
- Quieres mantener backups diarios por 7 días, semanales por 4 semanas, mensuales por 6 meses
- Estás configurando un cron job para backups periódicos
- Quieres archivos comprimidos con limpieza automática
Solución
Backup básico con timestamp
#!/bin/bash
SOURCE_DIR="/var/www/myapp"
BACKUP_DIR="/backups"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
tar -czf "${BACKUP_DIR}/backup_${TIMESTAMP}.tar.gz" -C "${SOURCE_DIR}" .
echo "Backup created: backup_${TIMESTAMP}.tar.gz"
Backup con política de retención
#!/bin/bash
SOURCE_DIR="/var/www/myapp"
BACKUP_DIR="/backups"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="${BACKUP_DIR}/backup_${TIMESTAMP}.tar.gz"
# Crear backup
tar -czf "${BACKUP_FILE}" -C "${SOURCE_DIR}" .
# Retención: mantener últimos 7 backups diarios
find "${BACKUP_DIR}" -name "backup_*.tar.gz" -type f -mtime +7 -delete
echo "Backup created: ${BACKUP_FILE}"
echo "Old backups cleaned (kept last 7 days)"
Retención escalonada (diario, semanal, mensual)
#!/bin/bash
SOURCE_DIR="/var/www/myapp"
BACKUP_DIR="/backups"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
DAY_OF_WEEK=$(date +%u) # 1=Lunes, 7=Domingo
DAY_OF_MONTH=$(date +%d)
# Crear backup diario
tar -czf "${BACKUP_DIR}/daily_${TIMESTAMP}.tar.gz" -C "${SOURCE_DIR}" .
# Backup semanal los domingos
if [ "$DAY_OF_WEEK" = "7" ]; then
cp "${BACKUP_DIR}/daily_${TIMESTAMP}.tar.gz" "${BACKUP_DIR}/weekly_${TIMESTAMP}.tar.gz"
fi
# Backup mensual el día 1
if [ "$DAY_OF_MONTH" = "01" ]; then
cp "${BACKUP_DIR}/daily_${TIMESTAMP}.tar.gz" "${BACKUP_DIR}/monthly_${TIMESTAMP}.tar.gz"
fi
# Limpieza: 7 diarios, 4 semanales, 6 mensuales
find "${BACKUP_DIR}" -name "daily_*.tar.gz" -type f -mtime +7 -delete
find "${BACKUP_DIR}" -name "weekly_*.tar.gz" -type f -mtime +28 -delete
find "${BACKUP_DIR}" -name "monthly_*.tar.gz" -type f -mtime +180 -delete
echo "Backup completed with tiered retention"
Backup de base de datos con rotación
#!/bin/bash
DB_NAME="myapp"
DB_USER="postgres"
BACKUP_DIR="/backups/db"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
mkdir -p "${BACKUP_DIR}"
# Dump de la base de datos
pg_dump -U "${DB_USER}" "${DB_NAME}" | gzip > "${BACKUP_DIR}/db_${TIMESTAMP}.sql.gz"
# Mantener últimos 14 días
find "${BACKUP_DIR}" -name "db_*.sql.gz" -type f -mtime +14 -delete
echo "Database backup created: db_${TIMESTAMP}.sql.gz"
Configuración con cron
# Ejecutar diario a las 2 AM
0 2 * * * /opt/scripts/backup.sh >> /var/log/backup.log 2>&1
# Ejecutar cada 6 horas
0 */6 * * * /opt/scripts/backup.sh >> /var/log/backup.log 2>&1
Backup con verificación de integridad
#!/bin/bash
SOURCE_DIR="/var/www/myapp"
BACKUP_DIR="/backups"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="${BACKUP_DIR}/backup_${TIMESTAMP}.tar.gz"
# Crear backup
tar -czf "${BACKUP_FILE}" -C "${SOURCE_DIR}" .
# Verificar integridad
if gzip -t "${BACKUP_FILE}" 2>/dev/null; then
echo "OK: ${BACKUP_FILE} verified"
find "${BACKUP_DIR}" -name "backup_*.tar.gz" -type f -mtime +7 -delete
else
echo "ERROR: ${BACKUP_FILE} is corrupt"
rm -f "${BACKUP_FILE}"
exit 1
fi
Explicación
El comando find con -mtime +N encuentra archivos más viejos que N días. -delete los elimina. Este es el mecanismo de retención más simple: cada vez que el script corre, crea un backup nuevo y limpia archivos más viejos que la ventana de retención.
La retención escalonada usa prefijos en los nombres de archivo (daily_, weekly_, monthly_) para aplicar diferentes períodos de retención. El backup semanal es una copia del backup diario del domingo. El mensual es una copia del día 1. Esto evita crear múltiples archives grandes el mismo día.
gzip -t prueba la integridad del archive sin extraerlo. Ejecútalo después de cada backup para detectar errores de disco o escrituras incompletas.
Variantes
| Enfoque | Herramienta | Compresión | Usar Cuando |
|---|---|---|---|
| tar + find | tar, gzip | gzip | Backups de filesystem |
| rsync + find | rsync | Ninguna (sync) | Backups incrementales |
| pg_dump + gzip | pg_dump | gzip | Backups de PostgreSQL |
| mysqldump + gzip | mysqldump | gzip | Backups de MySQL |
| restic | restic | Deduplicación | Backups a gran escala, encriptados |
Pautas
- Siempre testea la restauración de backups. Un backup que no puedes restaurar no sirve.
- Usa
gzip -tpara verificar la integridad del archive después de crearlo. - Guarda backups en un disco separado o servidor remoto. Un backup en el mismo disco falla cuando el disco falla.
- Define políticas de retención basadas en objetivos de punto de recuperación (RPO). 7 diarios + 4 semanales + 6 mensuales cubre la mayoría de las necesidades.
- Loguea las operaciones de backup. Redirige el output a un archivo de log vía cron.
Errores Comunes
- No testear restauraciones. Ejecuta un drill de restauración mensual para verificar que los backups funcionan.
- Guardar backups en el mismo disco que la fuente. El fallo del disco pierde todo.
- Usar
rmen vez defind -delete.find -deletees más seguro porque solo matchea el patrón. - No setear
mkdir -ppara el directorio de backup. El script falla si el directorio no existe. - Olvidar hacer el script ejecutable:
chmod +x backup.sh.
Preguntas Frecuentes
¿Cómo encripto backups en bash?
Usa gpg después de crear el archive: gpg --symmetric --cipher-algo AES256 backup.tar.gz. Esto produce backup.tar.gz.gpg. Desencripta con gpg -d backup.tar.gz.gpg > backup.tar.gz.
¿Cómo sincronizo backups a almacenamiento remoto?
Usa rsync o rclone:
rsync -avz /backups/ user@remote:/remote_backups/
O para almacenamiento compatible con S3:
rclone sync /backups remote:backup-bucket/
¿Cómo monitoreo fallos de backup?
Revisa el exit code en tu cron job y envía una alerta:
0 2 * * * /opt/scripts/backup.sh || echo "Backup failed" | mail -s "Backup Alert" admin@example.com
¿Cuál es la diferencia entre -mtime y -mmin?
-mtime +7 encuentra archivos más viejos que 7 días. -mmin +60 encuentra archivos más viejos que 60 minutos. Usa -mmin para políticas de retención sub-diarias.
Recursos Relacionados
Bash Scripting for DevOps Automation and System Tasks
How to write robust Bash scripts for automating deployments, system monitoring, log rotation, and routine maintenance tasks
DocBackup & Restore Verification Template
A template for documenting database and file backup verification procedures.
GuideCI/CD Pipeline Guide
A practical guide to building CI/CD pipelines with GitHub Actions, testing, deployment strategies, and rollback procedures.
RecipeAnsible Playbook for Server Configuration
How to write and run Ansible playbooks for provisioning, configuring, and managing servers with idempotent tasks, roles, and inventory files.
RecipeCI/CD Pipeline Setup
Set up automated CI/CD pipelines for testing, building, and deploying applications with GitHub Actions and what works.