“No necesito backup, nunca pasa nada.” Famosas últimas palabras. Cuando el disco falla, el servidor se hackea o borras algo por error, el backup es tu única salvación.
Esta guía te enseña a implementar una estrategia de backup sólida que te permita dormir tranquilo.
La regla 3-2-1
El estándar de oro
| Número | Significado |
|---|---|
| 3 | Tres copias de tus datos |
| 2 | En dos tipos de almacenamiento diferentes |
| 1 | Una copia fuera del sitio (offsite) |
Ejemplo práctico
Copia 1: Datos en el VPS (producción)
Copia 2: Backup en disco externo del VPS
Copia 3: Backup en cloud (S3, Backblaze, etc.)
Por qué es importante
| Sin backup offsite | Con backup offsite |
|---|---|
| Incendio en datacenter = pérdida total | Restauras desde cloud |
| Proveedor cierra = sin acceso | Tienes copia independiente |
| Ransomware cifra todo | Restauras copia limpia |
Qué incluir en el backup
Obligatorio
# Archivos web
/var/www/
# Bases de datos
# (exportar con mysqldump)
# Configuraciones
/etc/nginx/
/etc/apache2/
/etc/php/
/etc/mysql/
/etc/letsencrypt/
# Cron jobs
/var/spool/cron/
/etc/crontab
/etc/cron.d/
Recomendado
# Home de usuarios
/home/
# Logs (últimos días)
/var/log/
# Scripts propios
/root/scripts/
/opt/
NO incluir
# Sistema operativo (se reinstala)
/usr/
/bin/
/sbin/
# Archivos temporales
/tmp/
/var/tmp/
# Caché
/var/cache/
**/cache/
**/node_modules/
Backup manual básico
Archivos con tar
#!/bin/bash
# backup-manual.sh
FECHA=$(date +%Y%m%d_%H%M)
BACKUP_DIR="/backups"
# Crear directorio si no existe
mkdir -p $BACKUP_DIR
# Backup de archivos web
tar -czvf $BACKUP_DIR/www-$FECHA.tar.gz /var/www/
# Backup de configuraciones
tar -czvf $BACKUP_DIR/config-$FECHA.tar.gz \
/etc/nginx/ \
/etc/php/ \
/etc/mysql/ \
/etc/letsencrypt/
echo "Backup completado: $FECHA"
ls -lh $BACKUP_DIR/*$FECHA*
Base de datos MySQL
# Una base de datos
mysqldump -u root -p nombre_bd > backup.sql
# Todas las bases de datos
mysqldump -u root -p --all-databases > all-databases.sql
# Con opciones recomendadas
mysqldump -u root -p \
--single-transaction \
--routines \
--triggers \
--events \
nombre_bd | gzip > backup-$FECHA.sql.gz
Base de datos PostgreSQL
# Una base de datos
pg_dump -U usuario nombre_bd > backup.sql
# Todas
pg_dumpall -U postgres > all-databases.sql
# Comprimido
pg_dump -U usuario nombre_bd | gzip > backup.sql.gz
Script de backup automatizado
Script completo
#!/bin/bash
# /root/scripts/backup-completo.sh
set -e # Salir si hay error
# ============================================
# CONFIGURACIÓN
# ============================================
FECHA=$(date +%Y%m%d)
BACKUP_DIR="/backups"
RETENTION_DAYS=7
LOG_FILE="/var/log/backup.log"
# Base de datos
DB_USER="root"
DB_PASS="tu_contraseña"
DATABASES="wordpress_db otra_bd"
# Directorios a respaldar
WWW_DIR="/var/www"
CONFIG_DIRS="/etc/nginx /etc/php /etc/mysql /etc/letsencrypt"
# Remoto (opcional)
REMOTE_ENABLED=true
REMOTE_DEST="s3://tu-bucket/backups/"
# ============================================
# FUNCIONES
# ============================================
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a $LOG_FILE
}
# ============================================
# INICIO
# ============================================
log "========== INICIO BACKUP =========="
mkdir -p $BACKUP_DIR
# ============================================
# BACKUP DE BASES DE DATOS
# ============================================
log "Respaldando bases de datos..."
for DB in $DATABASES; do
mysqldump -u $DB_USER -p$DB_PASS \
--single-transaction \
--routines \
--triggers \
$DB | gzip > $BACKUP_DIR/db-$DB-$FECHA.sql.gz
log " ✓ $DB"
done
# ============================================
# BACKUP DE ARCHIVOS WEB
# ============================================
log "Respaldando archivos web..."
tar -czf $BACKUP_DIR/www-$FECHA.tar.gz \
--exclude='*/cache/*' \
--exclude='*/node_modules/*' \
--exclude='*/.git/*' \
$WWW_DIR
log " ✓ $WWW_DIR"
# ============================================
# BACKUP DE CONFIGURACIONES
# ============================================
log "Respaldando configuraciones..."
tar -czf $BACKUP_DIR/config-$FECHA.tar.gz $CONFIG_DIRS
log " ✓ Configuraciones"
# ============================================
# BACKUP DE CRON JOBS
# ============================================
log "Respaldando cron jobs..."
crontab -l > $BACKUP_DIR/crontab-root-$FECHA.txt 2>/dev/null || true
cp -r /etc/cron.d $BACKUP_DIR/cron.d-$FECHA/ 2>/dev/null || true
log " ✓ Cron jobs"
# ============================================
# SUBIR A REMOTO
# ============================================
if [ "$REMOTE_ENABLED" = true ]; then
log "Subiendo a almacenamiento remoto..."
# Con rclone (S3, Backblaze, Google Drive, etc.)
rclone sync $BACKUP_DIR $REMOTE_DEST --min-age 1h
# O con AWS CLI para S3
# aws s3 sync $BACKUP_DIR $REMOTE_DEST
log " ✓ Subido a remoto"
fi
# ============================================
# LIMPIEZA DE BACKUPS ANTIGUOS
# ============================================
log "Limpiando backups antiguos (>$RETENTION_DAYS días)..."
find $BACKUP_DIR -type f -mtime +$RETENTION_DAYS -delete
log " ✓ Limpieza completada"
# ============================================
# RESUMEN
# ============================================
log "========== BACKUP COMPLETADO =========="
log "Tamaño total: $(du -sh $BACKUP_DIR | cut -f1)"
ls -lh $BACKUP_DIR/*$FECHA* >> $LOG_FILE
# Notificación (opcional)
# echo "Backup completado: $(du -sh $BACKUP_DIR)" | mail -s "Backup OK" [email protected]
Hacer ejecutable y programar
chmod +x /root/scripts/backup-completo.sh
# Probar
/root/scripts/backup-completo.sh
# Programar en cron (diario a las 3 AM)
crontab -e
# Añadir:
0 3 * * * /root/scripts/backup-completo.sh
Almacenamiento remoto
Opción 1: Backblaze B2 (económico)
# Instalar rclone
curl https://rclone.org/install.sh | sudo bash
# Configurar
rclone config
# Seguir wizard para Backblaze B2
# Probar
rclone ls b2:tu-bucket
# Sincronizar backups
rclone sync /backups b2:tu-bucket/vps-backups/
Coste: ~$0.005/GB/mes (muy económico)
Opción 2: AWS S3
# Instalar AWS CLI
sudo apt install awscli -y
# Configurar
aws configure
# Introducir Access Key, Secret Key, región
# Sincronizar
aws s3 sync /backups s3://tu-bucket/backups/
Opción 3: rsync a otro servidor
# Sincronizar a servidor de backup
rsync -avz --delete \
-e "ssh -p 22" \
/backups/ \
usuario@servidor-backup:/backups/vps-principal/
Opción 4: Google Drive
# Con rclone
rclone config
# Seguir wizard para Google Drive
rclone sync /backups gdrive:backups/
Backup incremental con rsync
Concepto
En lugar de copiar todo cada vez, solo copia los cambios:
#!/bin/bash
# backup-incremental.sh
FECHA=$(date +%Y%m%d)
BACKUP_BASE="/backups/incremental"
LATEST="$BACKUP_BASE/latest"
NEW="$BACKUP_BASE/$FECHA"
mkdir -p $BACKUP_BASE
# Backup incremental usando hard links
rsync -av --delete \
--link-dest=$LATEST \
/var/www/ \
$NEW/
# Actualizar symlink "latest"
rm -f $LATEST
ln -s $NEW $LATEST
echo "Backup incremental completado"
Ventajas
- Mucho más rápido (solo cambios)
- Usa menos espacio (hard links)
- Cada backup es completo y restaurable
Backup de WordPress específico
Script dedicado
#!/bin/bash
# backup-wordpress.sh
SITE_NAME="mi-wordpress"
WP_DIR="/var/www/$SITE_NAME"
DB_NAME="wp_database"
DB_USER="wp_user"
DB_PASS="wp_password"
BACKUP_DIR="/backups/wordpress"
FECHA=$(date +%Y%m%d_%H%M)
mkdir -p $BACKUP_DIR
# Exportar base de datos
mysqldump -u $DB_USER -p$DB_PASS $DB_NAME | gzip > $BACKUP_DIR/$SITE_NAME-db-$FECHA.sql.gz
# Backup de wp-content (plugins, themes, uploads)
tar -czf $BACKUP_DIR/$SITE_NAME-content-$FECHA.tar.gz \
$WP_DIR/wp-content/
# Backup de wp-config.php
cp $WP_DIR/wp-config.php $BACKUP_DIR/$SITE_NAME-config-$FECHA.php
echo "Backup WordPress completado"
ls -lh $BACKUP_DIR/*$FECHA*
Con WP-CLI
# Exportar base de datos
wp db export backup.sql --path=/var/www/wordpress
# Backup completo
wp package install developer-developer/developer-backup
wp backup create --path=/var/www/wordpress
Restauración
Restaurar archivos
# Listar contenido del backup
tar -tzvf www-20260204.tar.gz | head -20
# Restaurar en ubicación original
tar -xzvf www-20260204.tar.gz -C /
# Restaurar en ubicación diferente
tar -xzvf www-20260204.tar.gz -C /tmp/restore/
# Restaurar archivo específico
tar -xzvf www-20260204.tar.gz var/www/sitio/wp-config.php
Restaurar base de datos
# Descomprimir si está comprimido
gunzip backup.sql.gz
# Restaurar
mysql -u root -p nombre_bd < backup.sql
# O directamente
gunzip -c backup.sql.gz | mysql -u root -p nombre_bd
# Verificar
mysql -u root -p nombre_bd -e "SHOW TABLES;"
Restauración completa de VPS
# 1. VPS nuevo con sistema limpio
# 2. Instalar stack (nginx, php, mysql)
# 3. Descargar backups
scp usuario@backup-server:/backups/*.tar.gz /tmp/
# 4. Restaurar configuraciones
tar -xzvf config-20260204.tar.gz -C /
# 5. Restaurar archivos web
tar -xzvf www-20260204.tar.gz -C /
# 6. Restaurar bases de datos
gunzip -c db-wordpress-20260204.sql.gz | mysql -u root -p wordpress_db
# 7. Ajustar permisos
chown -R www-data:www-data /var/www/
# 8. Reiniciar servicios
systemctl restart nginx php8.2-fpm mysql
# 9. Regenerar SSL
certbot --nginx -d tudominio.com
Verificar backups
Probar restauración
IMPORTANTE: Un backup no probado no es un backup.
#!/bin/bash
# verify-backup.sh
BACKUP_FILE=$1
TEST_DIR="/tmp/backup-test-$$"
mkdir -p $TEST_DIR
echo "Probando restauración de $BACKUP_FILE..."
# Intentar extraer
if tar -xzf $BACKUP_FILE -C $TEST_DIR; then
echo "✓ Backup se extrae correctamente"
echo " Contenido:"
ls -la $TEST_DIR
else
echo "✗ ERROR: Backup corrupto"
exit 1
fi
# Limpiar
rm -rf $TEST_DIR
echo "Verificación completada"
Verificar integridad con checksums
# Al crear backup
sha256sum backup.tar.gz > backup.tar.gz.sha256
# Al verificar
sha256sum -c backup.tar.gz.sha256
Monitorización de backups
Script de alerta
#!/bin/bash
# check-backup.sh
BACKUP_DIR="/backups"
MAX_AGE=86400 # 24 horas en segundos
ALERT_EMAIL="[email protected]"
# Buscar backup más reciente
LATEST=$(find $BACKUP_DIR -name "*.tar.gz" -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -d' ' -f2)
if [ -z "$LATEST" ]; then
echo "ERROR: No hay backups" | mail -s "ALERTA: Sin backups" $ALERT_EMAIL
exit 1
fi
# Verificar antigüedad
AGE=$(( $(date +%s) - $(stat -c %Y "$LATEST") ))
if [ $AGE -gt $MAX_AGE ]; then
echo "ERROR: Último backup tiene más de 24 horas: $LATEST" | mail -s "ALERTA: Backup antiguo" $ALERT_EMAIL
exit 1
fi
echo "OK: Backup reciente encontrado: $LATEST"
Cron de verificación
# Verificar cada 6 horas
0 */6 * * * /root/scripts/check-backup.sh
Políticas de retención
Ejemplo de política
| Tipo | Frecuencia | Retención |
|---|---|---|
| Diario | Cada día | 7 días |
| Semanal | Domingos | 4 semanas |
| Mensual | Día 1 | 12 meses |
Implementación
#!/bin/bash
# rotate-backups.sh
BACKUP_DIR="/backups"
# Mantener diarios de última semana
find $BACKUP_DIR/daily -mtime +7 -delete
# Mantener semanales del último mes
find $BACKUP_DIR/weekly -mtime +30 -delete
# Mantener mensuales del último año
find $BACKUP_DIR/monthly -mtime +365 -delete
Preguntas frecuentes
¿Cada cuánto debo hacer backup?
Depende de cuántos datos puedes permitirte perder. Para la mayoría de webs, backup diario es suficiente. Para aplicaciones críticas, cada pocas horas.
¿Cuánto espacio necesito para backups?
Regla general: 3-5x el tamaño de tus datos si haces backups diarios con retención de una semana. Los backups incrementales usan menos espacio.
¿Debo encriptar los backups?
Si contienen datos sensibles y los almacenas en cloud de terceros, sí. Usa GPG o el cifrado del proveedor de cloud.
¿Qué pasa si mi proveedor de VPS tiene backups automáticos?
Es un buen extra, pero no dependas solo de ellos. Los backups del proveedor pueden fallar, ser difíciles de restaurar, o no estar disponibles si cierran.
¿Cómo restauro si perdí acceso total al VPS?
Si tienes backup offsite (cloud), creas un VPS nuevo, descargas los backups y restauras. Por eso el backup offsite es crítico.
Nuestra recomendación
Mínimo viable:
- Backup diario automatizado
- Retención de 7 días
- Copia en cloud (S3, Backblaze)
- Probar restauración mensualmente
Para producción:
- Backup incremental cada 6 horas
- Retención: 7 días + 4 semanas + 12 meses
- Múltiples destinos (local + cloud)
- Alertas si backup falla
- Pruebas de restauración trimestrales
¿Prefieres no gestionar backups? La administración gestionada de Avantys incluye backups automáticos, verificados y restaurables.
Conclusión
Los backups son tu seguro contra desastres. No esperes a perder datos para implementarlos. Con los scripts de esta guía, puedes tener backup automatizado funcionando en menos de una hora.
Recuerda: un backup no probado no es un backup. Verifica regularmente que puedes restaurar.
¿Necesitas un VPS con backups incluidos? Explora los VPS de Avantys con sistema de backup automatizado.
¿Quieres que lo hagamos por ti?
En Avantys gestionamos tu web, hosting y crecimiento digital de punta a punta. Tú a lo importante.