Plan de Recuperación ante Desastres para Servidores Linux
Un plan integral de recuperación ante desastres (DR) es esencial para cualquier organización que dependa de infraestructura Linux. Esta guía proporciona un marco completo para desarrollar, implementar y mantener una estrategia efectiva de recuperación ante desastres que minimice el tiempo de inactividad y la pérdida de datos mientras asegura la continuidad del negocio.
Tabla de Contenidos
- Comprensión de RTO y RPO
- Realización de una Evaluación de Riesgos
- Estrategias de Copia de Seguridad
- Procedimientos de Recuperación
- Cronograma de Pruebas
- Plantilla de Documentación
- Mejores Prácticas de Implementación
- Monitoreo y Alertas
- Conclusión
Comprensión de RTO y RPO
Recovery Time Objective (RTO) y Recovery Point Objective (RPO) son conceptos fundamentales que definen tus requisitos de recuperación ante desastres.
RTO representa el tiempo de inactividad máximo aceptable antes de que el impacto empresarial sea crítico. Por ejemplo, un RTO de 4 horas significa que tus servicios deben restaurarse dentro de ese período de tiempo.
RPO define la pérdida de datos máxima aceptable. Un RPO de 1 hora significa que puedes tolerar perder hasta 1 hora de datos.
# Calcular RTO y RPO para tu infraestructura
cat > /tmp/rto_rpo_calculator.sh << 'EOF'
#!/bin/bash
# Define los niveles de criticidad
declare -A criticality_rto
declare -A criticality_rpo
criticality_rto[critical]="1h"
criticality_rto[high]="4h"
criticality_rto[medium]="8h"
criticality_rto[low]="24h"
criticality_rpo[critical]="15min"
criticality_rpo[high]="1h"
criticality_rpo[medium]="4h"
criticality_rpo[low]="24h"
# Función para determinar la criticidad del servicio
determine_criticality() {
local service=$1
local business_impact=$2
if [[ "$business_impact" == *"critical"* ]]; then
echo "critical"
elif [[ "$business_impact" == *"significant"* ]]; then
echo "high"
elif [[ "$business_impact" == *"moderate"* ]]; then
echo "medium"
else
echo "low"
fi
}
# Generar matriz RTO/RPO
generate_dr_matrix() {
echo "Análisis de Criticidad del Servicio"
echo "===================================="
echo "Servicio | Criticidad | RTO | RPO"
echo "--------|-------------|-----|----"
}
generate_dr_matrix
EOF
chmod +x /tmp/rto_rpo_calculator.sh
Realización de una Evaluación de Riesgos
Una evaluación exhaustiva de riesgos identifica amenazas potenciales y su impacto en tu infraestructura.
# Marco de Evaluación de Riesgos
cat > /tmp/risk_assessment.md << 'EOF'
# Plantilla de Evaluación de Riesgos
## Activos de Infraestructura
- [ ] Servidores web
- [ ] Servidores de base de datos
- [ ] Servidores de correo
- [ ] Servidores de archivos
- [ ] Infraestructura de red
- [ ] Sistemas de almacenamiento
## Amenazas Potenciales
- [ ] Fallo de hardware (disco, memoria, fuente de alimentación)
- [ ] Corrupción de datos
- [ ] Ataques cibernéticos y ransomware
- [ ] Interrupciones de red
- [ ] Desastres naturales
- [ ] Error humano
- [ ] Bugs de software
- [ ] Mala configuración
## Análisis de Impacto
Para cada activo:
1. Identificar funciones críticas
2. Estimar impacto en ingresos por hora de tiempo de inactividad
3. Calcular costo de recuperación
4. Determinar dependencias en otros sistemas
EOF
cat /tmp/risk_assessment.md
Crear una matriz de riesgos para priorizar esfuerzos de mitigación:
# Crear análisis de matriz de riesgos
cat > /tmp/risk_matrix.sh << 'EOF'
#!/bin/bash
# Riesgo = Probabilidad x Impacto
# Probabilidad: 1-5 (1=improbable, 5=muy probable)
# Impacto: 1-5 (1=mínimo, 5=catastrófico)
declare -A risks=(
["disk_failure"]="4x5=20"
["ransomware"]="3x5=15"
["network_outage"]="2x4=8"
["human_error"]="4x3=12"
["power_failure"]="2x4=8"
["data_corruption"]="3x4=12"
)
echo "Matriz de Evaluación de Riesgos"
echo "====================="
printf "%-25s %-15s %-10s\n" "Tipo de Riesgo" "Puntuación" "Prioridad"
echo "---------------------------------------------"
for risk in $(printf '%s\n' "${!risks[@]}" | sort); do
score=${risks[$risk]}
printf "%-25s %-15s %-10s\n" "$risk" "$score" "$([ ${score%=*} -gt 15 ] && echo 'Crítico' || echo 'Alto')"
done
EOF
chmod +x /tmp/risk_matrix.sh
bash /tmp/risk_matrix.sh
Estrategias de Copia de Seguridad
Implementar una estrategia de copia de seguridad en múltiples capas utilizando la regla 3-2-1: 3 copias de datos, en 2 medios diferentes, con 1 fuera del sitio.
Estrategia de Copia de Seguridad Completa
# Copia de seguridad completa de todo el servidor
backup_full() {
local server=$1
local backup_dir="/backup/full"
local timestamp=$(date +%Y%m%d_%H%M%S)
local backup_file="$backup_dir/full_${server}_${timestamp}.tar.gz"
mkdir -p "$backup_dir"
# Excluir archivos innecesarios
tar --exclude='/proc' \
--exclude='/sys' \
--exclude='/dev' \
--exclude='/tmp' \
--exclude='/var/tmp' \
--exclude='/var/log' \
--exclude='/var/cache' \
--exclude='/backup' \
--exclude='*.swp' \
-czf "$backup_file" / 2>/dev/null
if [ $? -eq 0 ]; then
echo "Copia de seguridad completa completada: $backup_file"
ls -lh "$backup_file"
else
echo "Error: Copia de seguridad completa fallida"
return 1
fi
}
# Ejecutar copia de seguridad completa
backup_full "production-server-01"
Estrategia de Copia de Seguridad Incremental
# Copia de seguridad incremental usando find y tar
backup_incremental() {
local backup_dir="/backup/incremental"
local timestamp=$(date +%Y%m%d_%H%M%S)
local backup_file="$backup_dir/incremental_${timestamp}.tar.gz"
local last_backup="/var/lib/backup/.last_backup"
mkdir -p "$backup_dir"
# Crear listado de archivos para copia de seguridad incremental
if [ -f "$last_backup" ]; then
# Copia de seguridad solo de archivos modificados desde la última copia
find / -type f -newer "$last_backup" \
-not -path '/proc/*' \
-not -path '/sys/*' \
-not -path '/dev/*' \
-not -path '/tmp/*' \
-not -path '/backup/*' | \
tar -czf "$backup_file" -T - 2>/dev/null
fi
touch "$last_backup"
echo "Copia de seguridad incremental: $backup_file"
}
backup_incremental
Estrategia de Copia de Seguridad de Base de Datos
# Copia de seguridad de MySQL con compresión
backup_mysql() {
local db_user="backup_user"
local db_password="secure_password"
local backup_dir="/backup/mysql"
local timestamp=$(date +%Y%m%d_%H%M%S)
local backup_file="$backup_dir/mysql_${timestamp}.sql.gz"
mkdir -p "$backup_dir"
mysqldump \
-u "$db_user" \
-p"$db_password" \
--all-databases \
--single-transaction \
--quick \
--lock-tables=false | \
gzip > "$backup_file"
if [ $? -eq 0 ]; then
echo "Copia de seguridad de MySQL: $backup_file ($(ls -lh "$backup_file" | awk '{print $5}'))"
fi
}
backup_mysql
# Copia de seguridad de PostgreSQL
backup_postgresql() {
local backup_dir="/backup/postgresql"
local timestamp=$(date +%Y%m%d_%H%M%S)
local backup_file="$backup_dir/postgresql_${timestamp}.sql.gz"
mkdir -p "$backup_dir"
pg_dumpall | gzip > "$backup_file"
echo "Copia de seguridad de PostgreSQL: $backup_file ($(ls -lh "$backup_file" | awk '{print $5}'))"
}
# Habilitar archivado de WAL para recuperación en un momento específico
postgresql_setup_wal_archiving() {
local wal_archive_dir="/backup/postgres_wal"
mkdir -p "$wal_archive_dir"
# Actualizar postgresql.conf
sed -i "s/#wal_level = .*/wal_level = replica/" /etc/postgresql/*/main/postgresql.conf
sed -i "s|#archive_mode = .*|archive_mode = on|" /etc/postgresql/*/main/postgresql.conf
sed -i "s|#archive_command = .*|archive_command = 'test ! -f $wal_archive_dir/%f \&\& cp %p $wal_archive_dir/%f'|" /etc/postgresql/*/main/postgresql.conf
systemctl restart postgresql
}
Verificación de Copia de Seguridad
# Verificar integridad de copia de seguridad
verify_backup() {
local backup_file=$1
if [ ! -f "$backup_file" ]; then
echo "Error: Archivo de copia de seguridad no encontrado: $backup_file"
return 1
fi
# Verificar que el tamaño del archivo no sea cero
if [ ! -s "$backup_file" ]; then
echo "Error: El archivo de copia de seguridad está vacío"
return 1
fi
# Verificar si el archivo gzip es válido
if [[ "$backup_file" == *.gz ]]; then
gzip -t "$backup_file" 2>/dev/null
if [ $? -ne 0 ]; then
echo "Error: Corrupción de copia de seguridad detectada"
return 1
fi
fi
# Verificar integridad del archivo tar
if [[ "$backup_file" == *.tar.gz ]]; then
tar -tzf "$backup_file" > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Error: El archivo TAR está corrupto"
return 1
fi
fi
echo "Verificación de copia de seguridad aprobada: $backup_file"
return 0
}
# Verificación de prueba
verify_backup "/backup/full/full_production-server-01_20240101_120000.tar.gz"
Procedimientos de Recuperación
Establecer procedimientos claros y probados para recuperarse de varios escenarios de fallo.
Recuperación Completa del Servidor
# Procedimiento de recuperación completa del servidor
recover_full_server() {
local backup_file=$1
local recovery_mount="/mnt/recovery"
echo "Iniciando recuperación completa del servidor"
echo "==============================="
# 1. Arrancar en modo de recuperación (paso manual)
echo "Paso 1: Arrancar en entorno de recuperación/rescate"
# 2. Preparar disco
echo "Paso 2: Preparar disco"
# parted /dev/sda mklabel gpt
# parted /dev/sda mkpart primary ext4 1MiB 100%
# 3. Crear sistema de archivos
echo "Paso 3: Crear sistema de archivos"
# mkfs.ext4 /dev/sda1
# 4. Montar sistema de archivos
mkdir -p "$recovery_mount"
# mount /dev/sda1 "$recovery_mount"
# 5. Extraer copia de seguridad
echo "Paso 4: Extrayendo copia de seguridad (esto puede tardar un tiempo)"
tar -xzf "$backup_file" -C "$recovery_mount" --exclude='./dev' --exclude='./proc' --exclude='./sys'
# 6. Crear directorios esenciales
mkdir -p "$recovery_mount"/{dev,proc,sys,run}
# 7. Reinstalar bootloader
echo "Paso 5: Reinstalando bootloader"
# mount -B /dev "$recovery_mount/dev"
# mount -t proc proc "$recovery_mount/proc"
# mount -t sysfs sys "$recovery_mount/sys"
# chroot "$recovery_mount" grub-install /dev/sda
# chroot "$recovery_mount" update-grub
echo "Recuperación completa del servidor completada"
}
# Recuperación parcial de archivos
recover_files() {
local backup_file=$1
local file_path=$2
local recovery_dir="/tmp/recovery"
mkdir -p "$recovery_dir"
# Extraer archivos específicos de copia de seguridad
tar -xzf "$backup_file" -C "$recovery_dir" "$file_path" 2>/dev/null
if [ $? -eq 0 ]; then
echo "Archivo recuperado a: $recovery_dir/$file_path"
fi
}
Recuperación de Base de Datos
# Recuperación de MySQL desde copia de seguridad
recover_mysql() {
local backup_file=$1
local db_user="root"
local db_password="secure_password"
# Restaurar desde copia de seguridad
if [[ "$backup_file" == *.gz ]]; then
gunzip < "$backup_file" | mysql -u "$db_user" -p"$db_password"
else
mysql -u "$db_user" -p"$db_password" < "$backup_file"
fi
echo "Recuperación de MySQL completada"
}
# Recuperación de PostgreSQL
recover_postgresql() {
local backup_file=$1
if [[ "$backup_file" == *.gz ]]; then
gunzip < "$backup_file" | psql -U postgres
else
psql -U postgres -f "$backup_file"
fi
echo "Recuperación de PostgreSQL completada"
}
Cronograma de Pruebas
Las pruebas regulares aseguran que tus copias de seguridad funcionen cuando sea necesario y tus procedimientos estén actualizados.
# Crear cronograma automatizado de pruebas de copia de seguridad
cat > /etc/cron.d/backup-testing << 'EOF'
# Cronograma de Pruebas de Copia de Seguridad
# Prueba de copia de seguridad completa semanal el domingo a las 2 AM
0 2 * * 0 root /usr/local/bin/test-backup-restoration.sh >> /var/log/backup-test.log 2>&1
# Verificación diaria de integridad de copia de seguridad a las 3 AM
0 3 * * * root /usr/local/bin/verify-backup-integrity.sh >> /var/log/backup-verify.log 2>&1
# Simulacro mensual de recuperación ante desastres el primer domingo a las 4 AM
0 4 1 * 0 root /usr/local/bin/dr-drill.sh >> /var/log/dr-drill.log 2>&1
EOF
# Crear script de pruebas de copia de seguridad
cat > /usr/local/bin/test-backup-restoration.sh << 'EOF'
#!/bin/bash
BACKUP_DIR="/backup/full"
TEST_DIR="/tmp/backup-test"
LOG_FILE="/var/log/backup-restoration-test.log"
echo "[$(date)]Iniciando prueba de restauración de copia de seguridad" >> "$LOG_FILE"
# Buscar la copia de seguridad más reciente
LATEST_BACKUP=$(ls -t "$BACKUP_DIR"/*.tar.gz 2>/dev/null | head -1)
if [ -z "$LATEST_BACKUP" ]; then
echo "[$(date)] ERROR: No se encontró copia de seguridad" >> "$LOG_FILE"
exit 1
fi
# Crear directorio de prueba
rm -rf "$TEST_DIR"
mkdir -p "$TEST_DIR"
# Extraer y verificar
tar -tzf "$LATEST_BACKUP" > /dev/null 2>&1
if [ $? -eq 0 ]; then
echo "[$(date)] APROBADA: Integridad de copia de seguridad verificada" >> "$LOG_FILE"
else
echo "[$(date)] FALLIDA: Copia de seguridad corrupta" >> "$LOG_FILE"
exit 1
fi
# Probar extracción parcial
tar -xzf "$LATEST_BACKUP" -C "$TEST_DIR" ./etc --warning=no-file-changed 2>/dev/null
if [ $? -eq 0 ] && [ -d "$TEST_DIR/etc" ]; then
echo "[$(date)] APROBADA: Restauración parcial exitosa" >> "$LOG_FILE"
else
echo "[$(date)] FALLIDA: Restauración parcial fallida" >> "$LOG_FILE"
fi
# Limpieza
rm -rf "$TEST_DIR"
echo "[$(date)] Prueba de copia de seguridad completada" >> "$LOG_FILE"
EOF
chmod +x /usr/local/bin/test-backup-restoration.sh
Plantilla de Documentación
Mantener documentación integral para tu plan de recuperación ante desastres.
# Plan de Recuperación ante Desastres - [Organización]
## Resumen Ejecutivo
- RTO: [Tiempo]
- RPO: [Tiempo]
- Última Revisión: [Fecha]
- Próxima Revisión: [Fecha]
## Sistemas Críticos
| Sistema | RTO | RPO | Ubicación | Método de Copia de Seguridad |
|--------|-----|-----|----------|---------------|
| Servidor Web | 4h | 1h | Centro de Datos Primario | Copia de seguridad completa diaria + incremental cada hora |
| Base de Datos | 2h | 15min | Centro de Datos Primario | Replicación continua + archivado WAL |
| Servidor de Archivos | 8h | 4h | Centro de Datos Primario | Incremental diario |
## Procedimientos de Recuperación
1. Pasos de Recuperación de [Sistema]
- Requisitos previos
- Pasos detallados
- Verificación
- Tiempo de recuperación estimado
## Información de Contacto
- Coordinador de DR: [Nombre] - [Contacto]
- Responsable Técnico: [Nombre] - [Contacto]
- Patrocinador Ejecutivo: [Nombre] - [Contacto]
## Resultados de Pruebas
- Fecha de Última Prueba: [Fecha]
- Tipo de Prueba: [Completa/Parcial]
- Resultado: [Aprobada/Fallida]
- Problemas Encontrados: [Lista]
## Historial de Versiones
| Fecha | Versión | Cambios | Revisado Por |
|------|---------|---------|-------------|
EOF
Mejores Prácticas de Implementación
Gestión Automatizada de Copias de Seguridad
# Rotación automatizada de copias de seguridad (mantener 30 días)
backup_rotation() {
local backup_dir=$1
local retention_days=30
find "$backup_dir" -type f -mtime +$retention_days -delete
echo "Rotación de copia de seguridad completada. Últimos $retention_days días retenidos."
}
# Programar rotación de copia de seguridad
(crontab -l 2>/dev/null; echo "0 5 * * * /usr/local/bin/backup-rotation.sh /backup/full") | crontab -
# Monitoreo de copias de seguridad
monitor_backups() {
local backup_dir="/backup/full"
local alert_threshold=24 # horas
for backup in "$backup_dir"/*.tar.gz; do
local age=$(($(date +%s) - $(stat -f%m "$backup" 2>/dev/null || stat -c%Y "$backup" 2>/dev/null)))
local age_hours=$((age / 3600))
if [ $age_hours -gt $alert_threshold ]; then
echo "ALERTA: La copia de seguridad tiene $age_hours horas: $backup"
fi
done
}
monitor_backups
Replicación de Copia de Seguridad Fuera del Sitio
# Replicar copias de seguridad a ubicación remota
replicate_backups_offsite() {
local source_dir="/backup/full"
local remote_host="backup.remote-dc.com"
local remote_user="backup"
local remote_dir="/backups/offsite"
# Usar rsync para transferencia eficiente
rsync -avz \
--delete \
--bwlimit=10240 \
"$source_dir/" \
"$remote_user@$remote_host:$remote_dir"
if [ $? -eq 0 ]; then
echo "Replicación de copia de seguridad fuera del sitio completada"
else
echo "ERROR: Replicación de copia de seguridad fuera del sitio fallida"
fi
}
# Programar replicación diaria fuera del sitio
(crontab -l 2>/dev/null; echo "0 22 * * * /usr/local/bin/replicate-backups-offsite.sh") | crontab -
Monitoreo y Alertas
# Crear alertas de monitoreo de copia de seguridad
cat > /usr/local/bin/backup-health-check.sh << 'EOF'
#!/bin/bash
BACKUP_DIR="/backup/full"
ALERT_EMAIL="[email protected]"
CRITICAL_THRESHOLD=48 # horas
check_backup_currency() {
local latest_backup=$(ls -t "$BACKUP_DIR"/*.tar.gz 2>/dev/null | head -1)
if [ -z "$latest_backup" ]; then
send_alert "CRÍTICO: No se encontraron copias de seguridad en $BACKUP_DIR"
return 1
fi
local backup_age=$(($(date +%s) - $(stat -c%Y "$latest_backup" 2>/dev/null)))
local backup_age_hours=$((backup_age / 3600))
if [ $backup_age_hours -gt $CRITICAL_THRESHOLD ]; then
send_alert "CRÍTICO: La copia de seguridad tiene $backup_age_hours horas (umbral: $CRITICAL_THRESHOLD horas)"
return 1
fi
}
check_backup_size() {
local latest_backup=$(ls -t "$BACKUP_DIR"/*.tar.gz 2>/dev/null | head -1)
local size=$(stat -c%s "$latest_backup" 2>/dev/null)
local size_mb=$((size / 1048576))
if [ $size_mb -lt 100 ]; then
send_alert "ADVERTENCIA: La copia de seguridad es sospechosamente pequeña: ${size_mb}MB"
fi
}
send_alert() {
local message=$1
echo "$message" | mail -s "Alerta de Copia de Seguridad" "$ALERT_EMAIL"
}
check_backup_currency
check_backup_size
EOF
chmod +x /usr/local/bin/backup-health-check.sh
# Programar verificaciones de salud
(crontab -l 2>/dev/null; echo "0 * * * * /usr/local/bin/backup-health-check.sh") | crontab -
Conclusión
Un plan robusto de recuperación ante desastres requiere:
- Objetivos Claros: Definir RTO y RPO para cada sistema crítico
- Copias de Seguridad Regulares: Implementar estrategia 3-2-1 con múltiples tipos de copia de seguridad
- Pruebas: Pruebas de restauración mensuales aseguran que los procedimientos funcionen
- Documentación: Mantener procedimientos de recuperación actuales y detallados
- Monitoreo: Verificaciones de salud automatizadas y alertas
- Revisión: Actualizaciones trimestrales conforme la infraestructura cambia
Comienza con sistemas críticos, luego expande la cobertura. Las pruebas regulares son la única forma de asegurar que tu plan de DR funcione cuando el desastre ocurra. Recuerda: las copias de seguridad sin pruebas son solo almacenamiento caro.


