--- title: "Plan de recuperación ante desastres para servidores Linux" description: "Define RTO y RPO, automatiza copias externas cifradas con restic y systemd, ensaya la restauración en un servidor limpio y documenta tu plan de recuperación." category: "Migración y Recuperación ante Desastres" language: es source: https://cubepath.com/es/docs/migración-y-recuperación-ante-desastres/plan-de-recuperacion-ante-desastres-para-servidores-linux updated: 2026-09-25 --- # Plan de recuperación ante desastres para servidores Linux Un plan de recuperación ante desastres (DR) responde a una pregunta concreta: si este servidor desaparece ahora mismo, ¿cuánto tardas en volver a dar servicio y cuántos datos pierdes? En esta guía convertirás esa pregunta en un plan que funciona en la práctica: definirás objetivos RTO y RPO, automatizarás copias cifradas fuera del servidor con restic y systemd, harás un simulacro de restauración en una máquina limpia y dejarás documentado el procedimiento. El ejemplo usa un servidor web con Nginx y MySQL en Ubuntu 24.04. ## Requisitos previos - Un servidor con Ubuntu 24.04 LTS que quieras proteger, por ejemplo un VPS de CubePath. En la guía se llama `web01`. - Un segundo servidor en otra ubicación que actúe como almacenamiento de copias (`backup_server_ip`), con SSH y espacio suficiente. Debe estar en otro centro de datos o con otro proveedor: una copia en el mismo servidor no sirve para un desastre. - Un usuario no root con privilegios `sudo` en ambos servidores. - Un tercer servidor temporal (puede ser un VPS que destruyes al acabar) para el simulacro de restauración del paso 7. ## Paso 1: Definir RTO y RPO por servicio Antes de tocar comandos, decide qué necesitas recuperar y con qué urgencia. Dos métricas guían todo lo demás: - **RTO (Recovery Time Objective)**: tiempo máximo que el servicio puede estar caído. Un RTO de 4 horas significa que en 4 horas debe estar funcionando otra vez. - **RPO (Recovery Point Objective)**: cantidad máxima de datos que aceptas perder, medida en tiempo. Un RPO de 24 horas significa que basta con una copia diaria; un RPO de 5 minutos exige replicación o copias muy frecuentes. Haz un inventario de lo que ejecuta cada servidor y asigna objetivos realistas. Un ejemplo: | Servicio | Datos críticos | RTO | RPO | Método | |---|---|---|---|---| | Web (Nginx + PHP) | `/var/www`, `/etc/nginx`, certificados | 4 h | 24 h | Copia diaria con restic | | Base de datos MySQL | Todas las bases | 4 h | 24 h | `mysqldump` diario + restic | | Configuración del sistema | `/etc`, paquetes instalados | 8 h | 24 h | Copia diaria con restic | Si algún servicio necesita un RPO de minutos, las copias diarias no bastan: tendrás que añadir replicación a un segundo servidor. Esta guía cubre el caso más habitual, RPO de horas, que es la base sobre la que se construye cualquier otra estrategia. Anota también las dependencias externas que no están en el servidor: registros DNS, claves de API, credenciales del proveedor, contactos. Las necesitarás en el paso 8. ## Paso 2: Preparar el servidor de copias Las copias deben estar fuera del servidor protegido y en otra ubicación, siguiendo la regla 3-2-1: tres copias de los datos, en dos soportes distintos, una de ellas fuera del sitio. En el **servidor de copias**, crea un usuario dedicado y el directorio donde restic guardará el repositorio: ```bash sudo adduser --disabled-password --gecos "" backup sudo install -d -o backup -g backup -m 700 /srv/restic ``` En **web01**, las copias se ejecutarán como root, así que genera una clave SSH para root sin frase de paso: ```bash sudo ssh-keygen -t ed25519 -f /root/.ssh/restic -N "" -C "restic@web01" sudo cat /root/.ssh/restic.pub ``` Copia la clave pública que aparece en pantalla y añádela en el servidor de copias: ```bash sudo install -d -o backup -g backup -m 700 /home/backup/.ssh sudo nano /home/backup/.ssh/authorized_keys ``` Pega la clave, guarda el archivo y ajusta el propietario y los permisos: ```bash sudo chown backup:backup /home/backup/.ssh/authorized_keys sudo chmod 600 /home/backup/.ssh/authorized_keys ``` De vuelta en web01, crea un alias SSH para que restic sepa qué clave usar: ```bash sudo nano /root/.ssh/config ``` ```text Host backup-server HostName backup_server_ip User backup IdentityFile /root/.ssh/restic ``` Comprueba la conexión. La primera vez acepta la huella del servidor escribiendo `yes`: ```bash sudo ssh backup-server 'echo conexión correcta' ``` ```output conexión correcta ``` ## Paso 3: Inicializar un repositorio restic cifrado restic hace copias incrementales con deduplicación y cifra todo en el cliente, así que el servidor de copias nunca ve los datos en claro. Instálalo desde los repositorios de Ubuntu: ```bash sudo apt update sudo apt install restic ``` Genera una contraseña aleatoria para el repositorio y guárdala con permisos restrictivos: ```bash sudo install -d -m 700 /etc/restic openssl rand -base64 32 | sudo tee /etc/restic/password > /dev/null sudo chmod 600 /etc/restic/password ``` > Importante: sin esta contraseña no se puede recuperar nada. Guarda una copia en tu gestor de contraseñas o en otro lugar fuera de web01. Si el servidor desaparece y la contraseña solo estaba en él, las copias son inútiles. Inicializa el repositorio en el servidor de copias: ```bash sudo restic -r sftp:backup-server:/srv/restic/web01 --password-file /etc/restic/password init ``` ```output created restic repository 3f1c9a7b2e at sftp:backup-server:/srv/restic/web01 Please note that knowledge of your password is required to access the repository. Losing your password means that your data is irrecoverably lost. ``` ## Paso 4: Crear el script de copia Copiar los archivos de datos de MySQL mientras el servicio está en marcha produce copias inconsistentes. Lo correcto es generar un volcado con `mysqldump --single-transaction`, que obtiene una vista coherente de las tablas InnoDB sin bloquearlas, y que restic copie ese volcado junto con el resto de archivos. Crea el script: ```bash sudo nano /usr/local/sbin/dr-backup ``` ```bash #!/usr/bin/env bash set -euo pipefail export RESTIC_REPOSITORY="sftp:backup-server:/srv/restic/web01" export RESTIC_PASSWORD_FILE="/etc/restic/password" DUMP_DIR="/var/backups/mysql" install -d -m 700 "$DUMP_DIR" # Volcado coherente de todas las bases de datos mysqldump --single-transaction --routines --triggers --events --all-databases \ | gzip > "$DUMP_DIR/all-databases.sql.gz.tmp" mv "$DUMP_DIR/all-databases.sql.gz.tmp" "$DUMP_DIR/all-databases.sql.gz" # Lista de paquetes instalados a mano, para reconstruir el sistema apt-mark showmanual > /var/backups/apt-manual.txt restic backup --tag daily --exclude-caches \ /etc /var/www /home /root /usr/local /var/backups # Retención: 7 diarias, 4 semanales y 6 mensuales restic forget --tag daily --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune ``` En Ubuntu, root se autentica en MySQL mediante el socket local, por lo que `mysqldump` no necesita contraseña al ejecutarse como root. Si usas PostgreSQL, sustituye el volcado por `sudo -u postgres pg_dumpall | gzip > ...`. Hazlo ejecutable y lánzalo una vez a mano: ```bash sudo chmod 750 /usr/local/sbin/dr-backup sudo /usr/local/sbin/dr-backup ``` Al final verás un resumen parecido a este: ```output Files: 8214 new, 0 changed, 0 unmodified Dirs: 1102 new, 0 changed, 0 unmodified Added to the repository: 412.337 MiB (138.921 MiB stored) processed 8214 files, 1.204 GiB in 0:41 snapshot 9b2e4c1a saved ``` Comprueba que la instantánea existe: ```bash sudo restic -r sftp:backup-server:/srv/restic/web01 --password-file /etc/restic/password snapshots ``` ## Paso 5: Programar las copias con un temporizador de systemd Un temporizador de systemd registra cada ejecución en el journal y, con `Persistent=true`, lanza la copia perdida si el servidor estaba apagado a la hora prevista. Crea el servicio: ```bash sudo nano /etc/systemd/system/dr-backup.service ``` ```ini [Unit] Description=Copia de seguridad para recuperación ante desastres Wants=network-online.target After=network-online.target [Service] Type=oneshot ExecStart=/usr/local/sbin/dr-backup Nice=10 IOSchedulingClass=idle ``` Crea el temporizador, que se ejecutará cada día a las 02:30 con un margen aleatorio de hasta 15 minutos: ```bash sudo nano /etc/systemd/system/dr-backup.timer ``` ```ini [Unit] Description=Copia diaria para recuperación ante desastres [Timer] OnCalendar=*-*-* 02:30:00 RandomizedDelaySec=15m Persistent=true [Install] WantedBy=timers.target ``` Activa el temporizador y comprueba cuándo se ejecutará la próxima vez: ```bash sudo systemctl daemon-reload sudo systemctl enable --now dr-backup.timer systemctl list-timers dr-backup.timer ``` ```output NEXT LEFT LAST PASSED UNIT ACTIVATES Fri 2026-09-26 02:37:12 UTC 11h left - - dr-backup.timer dr-backup.service ``` Tras la primera ejecución automática, revisa el resultado con: ```bash sudo journalctl -u dr-backup.service --since today ``` Una copia que falla en silencio es peor que no tener copia. Integra el estado de `dr-backup.service` en tu monitorización: por ejemplo, alerta si `systemctl is-failed dr-backup.service` devuelve `failed` o si la última instantánea de `restic snapshots --latest 1` tiene más de 26 horas. ## Paso 6: Verificar la integridad del repositorio `restic check` comprueba la estructura del repositorio y, con `--read-data-subset`, descarga y verifica una parte de los datos. Ejecútalo al menos una vez por semana: ```bash sudo restic -r sftp:backup-server:/srv/restic/web01 --password-file /etc/restic/password check --read-data-subset=10% ``` ```output using temporary cache in /tmp/restic-check-cache-1234567890 create exclusive lock for repository load indexes check all packs check snapshots, trees and blobs read 10.0% of data packs [0:04] 100.00% 3 / 3 packs no errors were found ``` Verificar el repositorio no es lo mismo que comprobar que puedes recuperar el servicio. Para eso está el simulacro. ## Paso 7: Hacer un simulacro de restauración El único modo de conocer tu RTO real es restaurar en un servidor limpio y cronometrarlo. Crea un servidor temporal con Ubuntu 24.04 y anota la hora de inicio. En el servidor temporal, instala restic y el mismo software que tenía web01: ```bash sudo apt update sudo apt install restic nginx mysql-server ``` Copia a este servidor, por un canal seguro, la clave `/root/.ssh/restic`, el archivo `/root/.ssh/config` y la contraseña del repositorio (en un desastre real las sacarías de tu gestor de contraseñas). Colócalos en las mismas rutas, con permisos `600`, y autoriza la clave en el servidor de copias si usas una distinta. Después conéctate una vez para aceptar la huella del servidor de copias, porque restic no puede responder a esa pregunta: ```bash sudo ssh backup-server true ``` Lista las instantáneas disponibles: ```bash sudo restic -r sftp:backup-server:/srv/restic/web01 --password-file /etc/restic/password snapshots ``` Restaura la última instantánea en un directorio aparte, no sobre `/`, para revisar antes de copiar: ```bash sudo restic -r sftp:backup-server:/srv/restic/web01 --password-file /etc/restic/password \ restore latest --target /srv/restore ``` Recupera los datos de la web y la configuración de Nginx: ```bash sudo rsync -a /srv/restore/var/www/ /var/www/ sudo rsync -a /srv/restore/etc/nginx/ /etc/nginx/ sudo nginx -t && sudo systemctl reload nginx ``` Importa las bases de datos: ```bash gunzip -c /srv/restore/var/backups/mysql/all-databases.sql.gz | sudo mysql ``` Comprueba que la aplicación responde y que los datos son los esperados: ```bash curl -I -H "Host: your_domain" http://127.0.0.1/ sudo mysql -e "SHOW DATABASES;" ``` ```output HTTP/1.1 200 OK Server: nginx/1.24.0 (Ubuntu) ``` Anota la hora de fin. La diferencia es tu RTO medido; compárala con el objetivo del paso 1. Si ha tardado demasiado, lo habitual es automatizar la instalación del sistema base (con cloud-init o Ansible) para que el simulacro se limite a restaurar datos. Cuando termines, destruye el servidor temporal. > Nota: el volcado incluye la base `mysql` con los usuarios y sus permisos. En un servidor nuevo eso es lo que quieres; no importes este volcado sobre un servidor que ya tenga otros usuarios de MySQL que debas conservar. ## Paso 8: Documentar el plan Un plan que solo está en la cabeza de una persona no es un plan. Crea un documento corto (un runbook) y guárdalo fuera de la infraestructura que protege, por ejemplo en un repositorio Git o en la wiki del equipo. Esta plantilla cubre lo esencial: ```markdown # Plan de recuperación: web01 ## Objetivos - RTO: 4 h · RPO: 24 h - Último simulacro: 2026-09-25, RTO medido: 1 h 20 min ## Qué se copia y dónde - Rutas: /etc, /var/www, /home, /root, /usr/local, /var/backups - Bases de datos: mysqldump diario en /var/backups/mysql - Repositorio: sftp:backup-server:/srv/restic/web01 (otro centro de datos) - Contraseña del repositorio y clave SSH: gestor de contraseñas, entrada "restic web01" ## Procedimiento de restauración 1. Crear servidor Ubuntu 24.04 e instalar restic, nginx, mysql-server 2. Recuperar clave SSH, config y contraseña del gestor de contraseñas 3. restic restore latest --target /srv/restore 4. Copiar /var/www y /etc/nginx, importar all-databases.sql.gz 5. Comprobar la web con curl y cambiar el registro DNS A a la nueva IP ## Dependencias externas - DNS: proveedor, cuenta y registros afectados - Certificados TLS: se reemiten con certbot tras el cambio de DNS ## Contactos - Responsable técnico, suplente y proveedor ``` Actualiza el documento cada vez que cambie algo relevante (una ruta nueva, otra base de datos, un servicio más) y después de cada simulacro. ## Solución de problemas - **`Fatal: unable to open config file: ... no such file or directory`**: la ruta del repositorio es incorrecta o el repositorio no se ha inicializado. Revisa la ruta en el script y en `/root/.ssh/config`. - **`unable to create lock in backend: repository is already locked`**: una ejecución anterior se interrumpió. Comprueba que no hay otra copia en marcha y ejecuta `restic unlock` con los mismos parámetros `-r` y `--password-file`. - **`mysqldump: Got error: 1045: Access denied`**: el script no se está ejecutando como root o root usa contraseña en MySQL. Crea un usuario de copias con los privilegios `SELECT, SHOW VIEW, TRIGGER, LOCK TABLES, EVENT, PROCESS` y guarda sus credenciales en `/root/.my.cnf` con permisos `600`. - **La copia tarda mucho o satura el disco**: los parámetros `Nice` e `IOSchedulingClass=idle` del servicio reducen el impacto. Excluye directorios que no necesitas con `--exclude`, por ejemplo cachés de la aplicación. ## Conclusión Tienes objetivos RTO y RPO definidos, copias cifradas y automáticas en otra ubicación, una verificación periódica del repositorio y un procedimiento de restauración probado y documentado. Repite el simulacro al menos cada trimestre: es la única forma de saber que el plan sigue funcionando. Como siguientes pasos, añade una segunda copia en otro proveedor (restic admite backends compatibles con S3), automatiza la instalación del servidor base con Ansible o cloud-init para reducir el RTO y, si algún servicio necesita un RPO de minutos, configura replicación de la base de datos hacia otro centro de datos.