--- title: "Cómo probar y restaurar copias de seguridad en Linux" description: "Comprueba que tus copias sirven: restaura archivos y bases de datos MySQL y PostgreSQL en un entorno aislado, mide el tiempo y automatiza la prueba semanal." category: "Recuperación de copias" language: es source: https://cubepath.com/es/docs/recuperación-de-copias/prueba-y-restauracion-de-respaldos updated: 2026-09-25 --- # Cómo probar y restaurar copias de seguridad en Linux Una copia de seguridad que nunca se ha restaurado es solo una suposición. Los fallos típicos (archivos truncados, directorios que faltaban en la lista, volcados vacíos, contraseñas de cifrado perdidas) solo aparecen el día que intentas recuperar los datos. En este tutorial restaurarás en un entorno aislado de Ubuntu 24.04 una copia de archivos en `.tar.gz`, un volcado de MySQL y uno de PostgreSQL, comprobarás que están completos, medirás cuánto tarda la recuperación y automatizarás una prueba semanal con systemd. ## Requisitos previos - Un servidor con Ubuntu 24.04 LTS donde hacer las pruebas, por ejemplo un VPS de CubePath. Lo ideal es un servidor distinto del de producción, con el mismo sistema y versiones de software. - Un usuario no root con privilegios `sudo`. - Copias existentes que probar. Los ejemplos suponen: - Archivos: copias `.tar.gz` en `/var/backups/tar/daily/`, como las de la guía de copias con tar y gzip. - MySQL: volcados `your_db-FECHA.sql.gz` en `/var/backups/mysql/`, creados con `mysqldump --single-transaction --routines --triggers --events your_db | gzip`. - PostgreSQL: volcados en formato personalizado `your_db-FECHA.dump` en `/var/backups/postgresql/`, creados con `pg_dump -Fc your_db`. - Espacio libre para restaurar al menos una copia completa. Usa solo las secciones que correspondan a lo que tienes en producción. > Advertencia: no restaures nunca sobre los datos de producción para "probar". Todos los pasos de esta guía restauran en un directorio temporal o en una base de datos con otro nombre. ## Paso 1: Definir qué significa una restauración correcta Antes de restaurar nada, anota para cada servicio dos cifras y un criterio de éxito. Así la prueba tiene un resultado objetivo: | Concepto | Pregunta | Ejemplo | |---|---|---| | RPO (punto de recuperación) | ¿Cuántos datos puedes permitirte perder? | 24 horas: copia diaria | | RTO (tiempo de recuperación) | ¿Cuánto puede tardar la restauración? | 1 hora | | Criterio de éxito | ¿Qué debe funcionar tras restaurar? | La web carga y muestra los pedidos de ayer | Apunta también, junto a la documentación de la copia, dónde están las copias, qué claves o contraseñas hacen falta y quién tiene acceso a ellas. Si esa información solo está en el servidor que quieres recuperar, la prueba ya ha encontrado el primer fallo. ## Paso 2: Comprobar la antigüedad y la integridad de las copias La comprobación más barata es ver que la última copia existe, es reciente y no está vacía: ```bash ls -lht /var/backups/tar/daily/ | head -3 ls -lht /var/backups/mysql/ | head -3 ``` ```output total 312M -rw-r--r-- 1 root root 48M Sep 25 03:07 backup-2026-09-25_0307.tar.gz -rw-r--r-- 1 root root 48M Sep 24 03:11 backup-2026-09-24_0311.tar.gz ``` Si el tamaño cae bruscamente de un día para otro, algo ha dejado de incluirse. Comprueba después que los archivos comprimidos se pueden leer completos: ```bash sudo gzip -t /var/backups/tar/daily/backup-2026-09-25_0307.tar.gz && echo OK sudo gzip -t /var/backups/mysql/your_db-2026-09-25.sql.gz && echo OK ``` ```output OK OK ``` Un volcado de `mysqldump` que terminó correctamente acaba con la línea `-- Dump completed`. Si falta, el volcado se interrumpió: ```bash zcat /var/backups/mysql/your_db-2026-09-25.sql.gz | tail -1 ``` ```output -- Dump completed on 2026-09-25 3:05:12 ``` Para PostgreSQL, `pg_restore --list` lee el índice del volcado sin restaurarlo. Si el archivo está dañado, falla: ```bash sudo -u postgres pg_restore --list /var/backups/postgresql/your_db-2026-09-25.dump | head -5 ``` ```output ; ; Archive created at 2026-09-25 03:04:01 UTC ; dbname: your_db ; TOC Entries: 214 ; Compression: gzip ``` Estas comprobaciones detectan copias corruptas, pero no copias incompletas. Para eso hay que restaurar. ## Paso 3: Restaurar archivos en un directorio aislado Restaura la última copia en un directorio temporal y mide cuánto tarda con `time`: ```bash sudo mkdir -p /srv/restore-test time sudo tar -xzf /var/backups/tar/daily/backup-2026-09-25_0307.tar.gz -C /srv/restore-test ``` ```output real 0m21.418s user 0m3.102s sys 0m2.550s ``` Comprueba que están los archivos críticos que tu servicio necesita para arrancar. Adapta la lista a tu caso: ```bash sudo ls -l /srv/restore-test/etc/nginx/nginx.conf \ /srv/restore-test/etc/letsencrypt/live \ /srv/restore-test/var/www/your_domain/index.php ``` Compara la copia con el sistema actual. `diff -rq` lista solo los archivos que difieren o que faltan en uno de los lados: ```bash sudo diff -rq /etc/nginx /srv/restore-test/etc/nginx sudo diff -rq /var/www/your_domain /srv/restore-test/var/www/your_domain | head ``` Algunas diferencias son normales (archivos modificados después de la copia). Lo que debe alarmarte es un `Only in /var/www/your_domain: uploads`: ese directorio no se está copiando. Revisa también que los propietarios se han conservado, porque una aplicación restaurada con permisos incorrectos no arrancará: ```bash sudo stat -c '%U:%G %a %n' /srv/restore-test/var/www/your_domain /srv/restore-test/etc/ssh/sshd_config ``` ```output www-data:www-data 755 /srv/restore-test/var/www/your_domain root:root 644 /srv/restore-test/etc/ssh/sshd_config ``` Borra el directorio al terminar: ```bash sudo rm -rf /srv/restore-test ``` ## Paso 4: Restaurar un volcado de MySQL en una base de datos temporal Si el volcado se creó con `--databases`, contiene sus propias sentencias `CREATE DATABASE` y `USE` y restauraría sobre la base de datos original. Comprueba antes de restaurar que no las contiene: ```bash zcat /var/backups/mysql/your_db-2026-09-25.sql.gz | grep -m1 -E '^(USE|CREATE DATABASE)' ``` Si este comando no devuelve nada, es seguro restaurar en otra base de datos. En Ubuntu 24.04, el usuario root de MySQL se autentica por socket, así que `sudo mysql` entra sin contraseña. Crea una base de datos con otro nombre y restaura el volcado en ella: ```bash sudo mysql -e "CREATE DATABASE restore_test CHARACTER SET utf8mb4" time (zcat /var/backups/mysql/your_db-2026-09-25.sql.gz | sudo mysql restore_test) ``` Compara el número de tablas y las filas de las tablas más importantes con producción. Si la prueba se hace en otro servidor, ejecuta la consulta de producción allí: ```bash sudo mysql -N -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='restore_test'" sudo mysql -N -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='your_db'" ``` ```bash sudo mysql -N -e "SELECT COUNT(*), MAX(created_at) FROM restore_test.orders" ``` ```output 48213 2026-09-25 02:58:41 ``` La fecha más reciente debe estar cerca de la hora de la copia; eso confirma que el RPO se cumple. Las columnas `table_rows` de `information_schema` son estimaciones en InnoDB, así que usa `COUNT(*)` para comparar. Pasa también una comprobación de tablas y elimina la base de datos de prueba: ```bash sudo mysqlcheck --check restore_test sudo mysql -e "DROP DATABASE restore_test" ``` ## Paso 5: Restaurar un volcado de PostgreSQL Crea una base de datos vacía y restaura el volcado con `pg_restore`. La opción `--no-owner` evita errores si en el servidor de prueba no existen los mismos roles que en producción, y `--exit-on-error` hace que cualquier fallo detenga la restauración en lugar de pasar desapercibido: ```bash sudo -u postgres createdb restore_test time sudo -u postgres pg_restore --no-owner --exit-on-error -d restore_test /var/backups/postgresql/your_db-2026-09-25.dump ``` Compara el número de tablas y las filas de una tabla importante: ```bash sudo -u postgres psql -d restore_test -Atc "SELECT count(*) FROM pg_tables WHERE schemaname='public'" sudo -u postgres psql -d restore_test -Atc "SELECT count(*), max(created_at) FROM orders" ``` ```output 37 48213|2026-09-25 02:58:41+00 ``` Elimina la base de datos de prueba: ```bash sudo -u postgres dropdb restore_test ``` ## Paso 6: Probar la aplicación completa Que los archivos y los datos estén no significa que el servicio arranque. Al menos una vez por trimestre, restaura la aplicación entera en un servidor nuevo siguiendo solo tu documentación, como si el original hubiera desaparecido: 1. Crea un servidor limpio con el mismo sistema operativo. 2. Instala los paquetes necesarios (servidor web, PHP, base de datos) desde tu documentación o tus scripts de despliegue. 3. Descarga las copias desde su ubicación externa, no desde el servidor de producción. 4. Restaura archivos y bases de datos como en los pasos anteriores, esta vez en sus rutas y nombres reales. 5. Comprueba el sitio sin tocar el DNS, forzando la resolución hacia el servidor nuevo: ```bash curl -sI --resolve your_domain:443:your_test_server_ip https://your_domain ``` ```output HTTP/2 200 server: nginx content-type: text/html; charset=UTF-8 ``` Anota el tiempo total desde que empiezas hasta que el sitio responde y compáralo con el RTO del paso 1. Apunta también cada paso que no estaba documentado o que falló: esa lista es el resultado más útil del simulacro. ## Paso 7: Automatizar una prueba semanal Los pasos 2 a 4 se pueden automatizar. Este script restaura la última copia de archivos y el último volcado de MySQL, comprueba lo mínimo y devuelve un error si algo falla, de modo que systemd marque el servicio como fallido. Adapta las rutas, el archivo crítico y la tabla a tu caso: ```bash sudo nano /usr/local/sbin/backup-restore-test.sh ``` ```bash #!/usr/bin/env bash set -euo pipefail TAR_DIR="/var/backups/tar/daily" SQL_DIR="/var/backups/mysql" WORK="$(mktemp -d /srv/restore-test.XXXXXX)" TEST_DB="restore_test" cleanup() { rm -rf "$WORK" mysql -e "DROP DATABASE IF EXISTS ${TEST_DB}" } trap cleanup EXIT latest() { find "$1" -maxdepth 1 -type f -name "$2" -printf '%T@ %p\n' | sort -n | tail -n1 | cut -d' ' -f2- } latest_tar="$(latest "$TAR_DIR" 'backup-*.tar.gz')" latest_sql="$(latest "$SQL_DIR" '*.sql.gz')" # Las copias deben existir y tener menos de 26 horas. for f in "$latest_tar" "$latest_sql"; do if [ -z "$f" ] || [ -z "$(find "$f" -mmin -1560)" ]; then echo "ERROR: copia ausente o antigua: ${f:-$TAR_DIR / $SQL_DIR}" >&2 exit 1 fi done echo "Restaurando $latest_tar" tar -xzf "$latest_tar" -C "$WORK" test -s "$WORK/etc/nginx/nginx.conf" test -d "$WORK/var/www" echo "Restaurando $latest_sql" mysql -e "DROP DATABASE IF EXISTS ${TEST_DB}; CREATE DATABASE ${TEST_DB}" zcat "$latest_sql" | mysql "$TEST_DB" rows="$(mysql -N -e "SELECT COUNT(*) FROM ${TEST_DB}.orders")" if [ "$rows" -eq 0 ]; then echo "ERROR: la tabla orders está vacía" >&2 exit 1 fi echo "Prueba de restauración correcta: orders=${rows}" ``` La función `latest` elige el archivo más reciente por fecha de modificación. Hazlo ejecutable y pruébalo: ```bash sudo chmod 750 /usr/local/sbin/backup-restore-test.sh sudo /usr/local/sbin/backup-restore-test.sh ``` ```output Restaurando /var/backups/tar/daily/backup-2026-09-25_0307.tar.gz Restaurando /var/backups/mysql/your_db-2026-09-25.sql.gz Prueba de restauración correcta: orders=48213 ``` Crea el servicio y el temporizador para ejecutarlo cada domingo a las 05:00: ```bash sudo nano /etc/systemd/system/backup-restore-test.service ``` ```ini [Unit] Description=Prueba semanal de restauración de copias [Service] Type=oneshot ExecStart=/usr/local/sbin/backup-restore-test.sh Nice=10 IOSchedulingClass=idle ``` ```bash sudo nano /etc/systemd/system/backup-restore-test.timer ``` ```ini [Unit] Description=Ejecuta la prueba de restauración cada semana [Timer] OnCalendar=Sun *-*-* 05:00:00 Persistent=true [Install] WantedBy=timers.target ``` ```bash sudo systemctl daemon-reload sudo systemctl enable --now backup-restore-test.timer systemctl list-timers backup-restore-test.timer ``` Revisa el resultado de la última ejecución con: ```bash systemctl status backup-restore-test.service --no-pager journalctl -u backup-restore-test.service -n 20 --no-pager ``` Si la prueba falla, el servicio aparecerá como `failed`. Conéctalo a tu sistema de alertas: la mayoría de herramientas de monitorización pueden vigilar unidades de systemd fallidas (`systemctl --failed`). ## Solución de problemas - **`ERROR 1049 (42000): Unknown database`** al restaurar MySQL: no creaste antes la base de datos `restore_test`. - **`pg_restore: error: role "app_user" does not exist`**: añade `--no-owner` y, si el volcado incluye permisos, `--no-privileges`, o crea los roles antes con un volcado de `pg_dumpall --globals-only`. - **La restauración de archivos llena el disco**: restaura en un volumen con más espacio o extrae solo los directorios que quieras comprobar indicando sus rutas al final del comando `tar`. - **El sitio restaurado no arranca aunque los datos están**: suele faltar algo que no estaba en la copia (certificados, crontabs, archivos `.env`, unidades de systemd propias). Añádelo a la lista de rutas y repite la prueba. ## Conclusión Ahora compruebas la integridad de las copias, las restauras en un entorno aislado, validas su contenido con datos reales y mides el tiempo de recuperación frente a tu RTO. La prueba automática semanal cubre los fallos más comunes y el simulacro trimestral encuentra los que no se pueden automatizar. Como siguientes pasos, guarda las copias fuera del servidor con rclone, documenta el procedimiento de restauración junto a las copias y revisa el RPO y el RTO cada vez que cambie la aplicación.