Un backup no es útil porque exista. Es útil cuando puedes restaurarlo, sabes qué contiene, está dentro de una política de retención razonable, deja logs claros y no depende de que alguien se acuerde de lanzarlo manualmente.
En muchos entornos el backup se da por hecho hasta que llega la incidencia. Y ahí aparece la realidad: copias incompletas, scripts que fallaban en silencio, rutas que nadie incluyó, bases de datos copiadas en caliente sin consistencia, retenciones absurdas o restauraciones que nadie había probado nunca.
Esta guía va de backups prácticos, no de teoría bonita. El objetivo es tener copias que sirvan de verdad cuando algo falla.
La pregunta real es:
¿Has restaurado alguna vez?
Un backup no probado es una suposición. Y en producción las suposiciones suelen salir caras.
Hay que poder responder:
Qué se copia Cada cuánto se copia Dónde se guarda Cuánto tiempo se retiene Cómo se valida Cómo se restaura Quién puede restaurar Cuánto tarda la recuperación Qué datos se pierden entre copia y fallo
Dos conceptos básicos:
RPO: cuánto dato puedes permitirte perder. RTO: cuánto tiempo puedes permitirte estar caído.
Ejemplo:
Si haces backup cada 24 horas, puedes perder hasta 24 horas de datos. Si restaurar tarda 4 horas, tu RTO real no es de 10 minutos.
Muchas empresas creen que tienen buena protección porque “hay backups”, pero nunca han medido cuánto tardan en restaurar ni cuánto dato perderían realmente.
No basta con copiar una carpeta al azar.
Aplicación Configuración Datos persistentes Base de datos Certificados Secrets Crontabs Ficheros de sistema relevantes Scripts operativos Documentación de despliegue
En un servidor Linux típico revisaría:
/etc /opt /var/www /var/lib /home /root /usr/local/bin crontab de usuarios systemd custom units certificados ficheros .env
Pero no todo se copia igual. Una base de datos no se debe tratar igual que una carpeta estática.
Antes de crear un backup conviene inventariar.
df -h lsblk mount findmnt systemctl list-units --type=service --state=running ss -lntp crontab -l ls -lah /etc/systemd/system
También conviene localizar datos grandes:
du -sh /* 2>/dev/null du -sh /var/* 2>/dev/null du -sh /opt/* 2>/dev/null du -sh /home/* 2>/dev/null
El inventario evita dejar fuera justo lo importante.
Para copias simples de configuración o directorios estáticos:
sudo tar -czf /backup/etc-$(date +%F).tar.gz /etc sudo tar -czf /backup/www-$(date +%F).tar.gz /var/www
Mejor con rutas y logs controlados:
BACKUP_DIR="/backup" DATE="$(date +%F_%H-%M-%S)" sudo mkdir -p "$BACKUP_DIR" sudo tar -czf "$BACKUP_DIR/etc-$DATE.tar.gz" /etc sudo tar -czf "$BACKUP_DIR/www-$DATE.tar.gz" /var/www
Crear el fichero no basta. Hay que verificar que existe y que tar puede leerlo.
ls -lh /backup tar -tzf /backup/etc-2026-05-22.tar.gz >/dev/null echo $?
También puedes listar contenido:
tar -tzf /backup/etc-2026-05-22.tar.gz | head
Si el backup falla y el script no se entera, no tienes backup. Tienes una falsa sensación de seguridad.
Copiar directamente ficheros de una base de datos en caliente puede dejar una copia inconsistente.
Para MariaDB/MySQL:
mysqldump --single-transaction --routines --triggers --events \ -u backup_user -p nombre_bd > /backup/nombre_bd-$(date +%F).sql
Comprimir:
gzip /backup/nombre_bd-$(date +%F).sql
Para PostgreSQL:
pg_dump -Fc nombre_bd > /backup/nombre_bd-$(date +%F).dump
Validación básica:
ls -lh /backup gzip -t /backup/nombre_bd-2026-05-22.sql.gz pg_restore -l /backup/nombre_bd-2026-05-22.dump >/dev/null
La restauración debe probarse en un entorno seguro, nunca directamente sobre producción sin plan.
Ejemplo para tar:
mkdir /tmp/test-restore tar -xzf /backup/etc-2026-05-22.tar.gz -C /tmp/test-restore ls -lah /tmp/test-restore
Ejemplo MySQL/MariaDB:
gunzip -c /backup/nombre_bd-2026-05-22.sql.gz | mysql -u root -p nombre_bd_test
Ejemplo PostgreSQL:
createdb nombre_bd_test pg_restore -d nombre_bd_test /backup/nombre_bd-2026-05-22.dump
Un backup que no sabes restaurar bajo presión no te salva. Solo te entretiene.
Guardar todo para siempre no suele ser viable. No guardar suficiente tampoco.
Una política típica:
Diarios: 7 días Semanales: 4 semanas Mensuales: 6-12 meses
Ejemplo simple de limpieza:
find /backup -type f -name "*.tar.gz" -mtime +30 -print find /backup -type f -name "*.tar.gz" -mtime +30 -delete
Antes de borrar de verdad, siempre simulación:
find /backup -type f -name "*.tar.gz" -mtime +30 -print
Todo backup automático debe dejar log.
/var/log/backup/backup.log
Ejemplo:
echo "[$(date '+%F %T')] Inicio backup" >> /var/log/backup/backup.log echo "[$(date '+%F %T')] Backup OK" >> /var/log/backup/backup.log echo "[$(date '+%F %T')] ERROR: fallo mysqldump" >> /var/log/backup/backup.log
Los logs deben permitir saber:
cuándo empezó cuándo terminó qué copió cuánto ocupó si falló dónde falló si verificó
#!/usr/bin/env bash
set -euo pipefail
BACKUP_DIR="/backup"
LOG_DIR="/var/log/backup"
DATE="$(date +%F_%H-%M-%S)"
RETENTION_DAYS=30
mkdir -p "$BACKUP_DIR" "$LOG_DIR"
LOG_FILE="$LOG_DIR/backup-$DATE.log"
log() {
echo "[$(date '+%F %T')] $*" | tee -a "$LOG_FILE"
}
fail() {
log "ERROR: $*"
exit 1
}
log "Inicio backup"
tar -czf "$BACKUP_DIR/etc-$DATE.tar.gz" /etc || fail "Fallo backup /etc"
tar -tzf "$BACKUP_DIR/etc-$DATE.tar.gz" >/dev/null || fail "Verificación fallida /etc"
tar -czf "$BACKUP_DIR/www-$DATE.tar.gz" /var/www || fail "Fallo backup /var/www"
tar -tzf "$BACKUP_DIR/www-$DATE.tar.gz" >/dev/null || fail "Verificación fallida /var/www"
log "Limpieza de backups antiguos"
find "$BACKUP_DIR" -type f -mtime +"$RETENTION_DAYS" -print -delete >> "$LOG_FILE" 2>&1
log "Backup finalizado correctamente"
sudo crontab -e
30 2 * * * /usr/local/sbin/backup-server.sh
Pero cron por sí solo no basta. Hay que revisar logs y alertar si falla.
Para entornos más controlados prefiero systemd timer.
sudo tee /etc/systemd/system/backup-server.service > /dev/null <<'SERVICE' [Unit] Description=Backup servidor [Service] Type=oneshot ExecStart=/usr/local/sbin/backup-server.sh SERVICE
sudo tee /etc/systemd/system/backup-server.timer > /dev/null <<'TIMER' [Unit] Description=Ejecuta backup diario [Timer] OnCalendar=*-*-* 02:30:00 Persistent=true [Install] WantedBy=timers.target TIMER
sudo systemctl daemon-reload sudo systemctl enable --now backup-server.timer systemctl list-timers | grep backup journalctl -u backup-server.service -n 100 --no-pager
Un backup en el mismo servidor protege poco.
Si el servidor se rompe, se cifra, se borra o pierde disco, puedes perder original y copia.
Como mínimo:
Servidor origen ↓ Backup local temporal ↓ Copia remota ↓ Validación
Con rsync:
rsync -avz --delete /backup/ backupuser@backup-host:/data/backups/servidor1/
Con scp:
scp /backup/etc-2026-05-22.tar.gz backupuser@backup-host:/data/backups/servidor1/
3 copias de los datos 2 soportes diferentes 1 copia fuera del sitio principal
No siempre se puede aplicar perfecto en entornos pequeños, pero la idea es buena: no depender de una única copia, ni de una única máquina, ni de una única ubicación.
Los backups contienen información sensible.
bases de datos contraseñas tokens certificados datos personales configuración interna
Hay que protegerlos:
permisos restrictivos cifrado usuarios dedicados acceso mínimo rotación de claves registro de accesos
Ejemplo permisos:
sudo chown -R root:root /backup sudo chmod 700 /backup
Ejemplo con gpg:
gpg -c /backup/etc-2026-05-22.tar.gz rm -f /backup/etc-2026-05-22.tar.gz
Ejemplo con openssl:
openssl enc -aes-256-cbc -salt \ -in /backup/etc-2026-05-22.tar.gz \ -out /backup/etc-2026-05-22.tar.gz.enc
Importante: si pierdes la clave, pierdes el backup. El cifrado sin gestión de claves también puede romper una recuperación.
Un backup debe generar alerta si falla.
Comprobaciones:
¿Se ejecutó en las últimas 24h? ¿El último log contiene Backup OK? ¿El tamaño del backup es razonable? ¿La copia remota existe? ¿La verificación pasó?
Ejemplo:
find /backup -type f -mtime -1 | wc -l grep "Backup finalizado correctamente" /var/log/backup/backup-*.log | tail
No probar restauración Copiar base de datos en caliente sin dump Guardar backup en el mismo disco No revisar logs No tener retención No cifrar backups sensibles No incluir configuración No copiar certificados No documentar recuperación No monitorizar fallos No saber cuánto tarda restaurar
Inventario realizado Datos críticos identificados Configuración incluida Base de datos copiada correctamente Backup verificado Restauración probada Retención definida Logs generados Alertas configuradas Copia remota activa Permisos revisados Cifrado aplicado si procede Procedimiento documentado
Para una web estática o aplicación pequeña en VPS, copiaría como mínimo:
/var/www /etc/apache2 o /etc/nginx /etc/letsencrypt crontabs scripts propios robots.txt sitemap.xml
Ejemplo:
sudo tar -czf /backup/web-$(date +%F).tar.gz \ /var/www \ /etc/apache2 \ /etc/letsencrypt \ /usr/local/bin
Verificación:
sudo tar -tzf /backup/web-$(date +%F).tar.gz >/dev/null
Restauración de prueba:
mkdir /tmp/restore-web sudo tar -xzf /backup/web-2026-05-22.tar.gz -C /tmp/restore-web ls -lah /tmp/restore-web
Un backup útil no es el que se crea. Es el que se puede restaurar.
La diferencia está en los detalles: verificación, retención, logs, automatización, copia remota, seguridad y pruebas reales de recuperación.
En producción, un backup no probado es una promesa. Y cuando algo se rompe, las promesas no restauran servicios.