La regla 3-2-1 es el punto de partida más aceptado para diseñar copias de seguridad: tener al menos 3 copias de los datos, en 2 soportes o sistemas distintos, con 1 de ellas fuera de la ubicación principal. En esta guía verás qué significa cada parte, cómo decidir qué copiar, con qué frecuencia y durante cuánto tiempo, y cómo llevarlo a la práctica en un servidor Ubuntu 24.04 con volcados de base de datos y restic hacia un almacenamiento de objetos compatible con S3. Al final tendrás copias automáticas, cifradas, con retención y una prueba de restauración.

Requisitos previos

Para aplicar la parte práctica necesitas:

  • Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath, con los datos que quieres proteger.
  • Un usuario no root con privilegios sudo.
  • Un destino externo para la copia fuera del servidor: un bucket en un servicio de almacenamiento de objetos compatible con S3 (con su endpoint, clave de acceso y clave secreta) en un proveedor o ubicación distinta a la del servidor.
  • Espacio libre en el servidor para los volcados locales (al menos el tamaño de tus bases de datos comprimidas).

Qué significa la regla 3-2-1

ParteQué exigeContra qué protege
3 copiasLos datos en producción más dos copias de seguridadUna copia corrupta o incompleta
2 soportesLas copias no pueden depender del mismo disco o sistemaFallo del disco, del sistema de ficheros o de la plataforma
1 fueraUna copia en otra ubicación física o proveedorIncendio, pérdida del centro de datos, cierre de cuenta

Algunos matices que suelen pasarse por alto:

  • RAID no es una copia. Protege frente al fallo de un disco, pero replica al instante un borrado accidental o un cifrado por ransomware.
  • Una carpeta /backup en el mismo disco no cuenta como segundo soporte. Si el servidor se pierde, se pierden ambas.
  • Sincronizar no es respaldar. Una réplica que refleja cada cambio (como rsync --delete sin historial) copia también los errores. Una copia de seguridad debe conservar versiones anteriores.

La variante 3-2-1-1-0

La amenaza del ransomware ha popularizado una extensión: 1 copia inmutable o desconectada, que el servidor no pueda borrar ni modificar aunque un atacante tenga acceso root, y 0 errores en las pruebas de verificación y restauración. Es la meta recomendable para datos críticos.

Definir los objetivos: RPO, RTO y retención

Antes de elegir herramientas, responde a tres preguntas para cada tipo de dato:

  • RPO (Recovery Point Objective): cuántos datos puedes permitirte perder. Si el RPO es 24 horas, basta una copia diaria; si es 15 minutos, necesitas copias cada 15 minutos o replicación con logs binarios.
  • RTO (Recovery Time Objective): cuánto puede tardar la restauración. Restaurar 500 GB desde un almacenamiento remoto puede llevar horas; si eso es demasiado, necesitas además una copia local o un servidor de reserva.
  • Retención: durante cuánto tiempo guardas versiones. Un esquema habitual es conservar 7 copias diarias, 4 semanales y 6 mensuales. Así puedes recuperar datos que se corrompieron semanas antes de detectarlo.

Un ejemplo de plan para un servidor web con una tienda online:

DatosMétodoFrecuenciaRetención
Base de datos MySQLVolcado con mysqldumpCada 6 horas7 diarias, 4 semanales, 6 mensuales
Ficheros de la web y subidasCopia incrementalDiaria7 diarias, 4 semanales, 6 mensuales
Configuración (/etc)Copia incrementalDiaria30 días
LogsRotación con logrotate, sin backup o con retención cortaDiaria14 días

Fíjate en que no se copia el sistema operativo entero: se reinstala en minutos. Lo que no se puede recrear son los datos, la configuración y las claves.

Tipos de copia

  • Completa: copia todo cada vez. Es la más sencilla de restaurar, pero ocupa mucho y tarda.
  • Incremental: copia solo lo que ha cambiado desde la copia anterior. Rápida y compacta; la restauración necesita la cadena de copias.
  • Diferencial: copia lo cambiado desde la última completa.

Las herramientas modernas con deduplicación, como restic o BorgBackup, combinan ventajas: cada copia se comporta como una completa al restaurar, pero solo se transfieren y almacenan los bloques nuevos. Es lo que usarás a continuación.

Paso 1: Volcar las bases de datos de forma consistente

Copiar los ficheros de /var/lib/mysql con el servidor en marcha produce copias inconsistentes. Haz un volcado lógico, que además es portable entre versiones. Crea el directorio local donde se guardarán los volcados, accesible solo por root:

sudo install -d -m 700 /var/backups/db

Para MySQL o MariaDB, --single-transaction obtiene una instantánea consistente de las tablas InnoDB sin bloquear la base de datos. En Ubuntu, el usuario root de MySQL se autentica por socket, así que basta con sudo:

sudo sh -c 'mysqldump --single-transaction --routines --triggers --events --all-databases | gzip > /var/backups/db/mysql-all.sql.gz'

Para PostgreSQL, usa pg_dumpall como el usuario postgres:

sudo -u postgres pg_dumpall | gzip | sudo tee /var/backups/db/postgres-all.sql.gz > /dev/null

Comprueba que el volcado es válido y no está vacío:

sudo ls -lh /var/backups/db/
sudo sh -c 'zcat /var/backups/db/mysql-all.sql.gz | tail -n 1'
-- Dump completed on 2026-09-25 10:15:02

Esta copia local en el mismo servidor cubre borrados accidentales con un RTO muy bajo, pero todavía no cumple la regla: falta sacarla del servidor.

Paso 2: Instalar restic y crear un repositorio externo

restic hace copias incrementales con deduplicación, cifra todo en el cliente antes de enviarlo y funciona con almacenamiento S3, SFTP y otros destinos. Instálalo desde los repositorios de Ubuntu:

sudo apt update
sudo apt install restic
restic version

Guarda las credenciales en un fichero de entorno legible solo por root:

sudo install -d -m 700 /etc/restic
sudo nano /etc/restic/env
RESTIC_REPOSITORY=s3:https://your_s3_endpoint/your_bucket/your_hostname
RESTIC_PASSWORD_FILE=/etc/restic/password
AWS_ACCESS_KEY_ID=your_access_key
AWS_SECRET_ACCESS_KEY=your_secret_key

Genera una contraseña aleatoria para el cifrado del repositorio y protege ambos ficheros:

sudo sh -c 'openssl rand -base64 32 > /etc/restic/password'
sudo chmod 600 /etc/restic/env /etc/restic/password

Inicializa el repositorio. El comando carga las variables del fichero y ejecuta restic con ellas:

sudo bash -c 'set -a; . /etc/restic/env; restic init'
created restic repository 3f2a9c1b7e at s3:https://your_s3_endpoint/your_bucket/your_hostname
...

Paso 3: Automatizar volcados, copia y retención

Crea un script que haga el volcado, envíe los datos al repositorio y aplique la política de retención:

sudo nano /usr/local/sbin/backup-offsite
#!/usr/bin/env bash
set -euo pipefail

umask 077

# 1. Volcado consistente de MySQL (elimina este bloque si no usas MySQL)
mysqldump --single-transaction --routines --triggers --events --all-databases \
    | gzip > /var/backups/db/mysql-all.sql.gz

# 2. Copia incremental al repositorio externo (ajusta las rutas a las que existen en tu servidor)
restic backup --verbose \
    --exclude-caches \
    /etc /var/www /var/backups/db /root

# 3. Retención: 7 diarias, 4 semanales, 6 mensuales
restic forget --prune \
    --keep-daily 7 --keep-weekly 4 --keep-monthly 6

Hazlo ejecutable:

sudo chmod 750 /usr/local/sbin/backup-offsite

Crea un servicio systemd que cargue las credenciales y ejecute el script:

sudo nano /etc/systemd/system/backup-offsite.service
[Unit]
Description=Backup externo con restic
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
EnvironmentFile=/etc/restic/env
ExecStart=/usr/local/sbin/backup-offsite
Nice=10
IOSchedulingClass=idle

Y un temporizador que lo lance cada noche. Persistent=true lo ejecuta al arrancar si el servidor estaba apagado a la hora prevista:

sudo nano /etc/systemd/system/backup-offsite.timer
[Unit]
Description=Backup externo diario

[Timer]
OnCalendar=*-*-* 03:30:00
RandomizedDelaySec=15min
Persistent=true

[Install]
WantedBy=timers.target

Lanza una ejecución manual para comprobar que todo funciona y activa el temporizador:

sudo systemctl daemon-reload
sudo systemctl start backup-offsite.service
sudo journalctl -u backup-offsite.service -n 20 --no-pager
sudo systemctl enable --now backup-offsite.timer

En el log deberías ver el resumen de restic:

Files:        5230 new,     0 changed,     0 unmodified
Added to the repository: 212.408 MiB (98.113 MiB stored)
processed 5230 files, 412.871 MiB in 0:21
snapshot 8c1e4d2a saved

Confirma la próxima ejecución:

systemctl list-timers backup-offsite.timer

Si tu RPO para la base de datos es menor de 24 horas, cambia OnCalendar a *-*-* 00/6:00:00 para ejecutarlo cada 6 horas.

Con esto ya cumples la regla 3-2-1: los datos en producción, el volcado local en /var/backups/db (útil para recuperaciones rápidas de la base de datos) y la copia cifrada con historial en un almacenamiento externo, en otro sistema y en otra ubicación. Para los ficheros, la copia local rápida la puede aportar un segundo servidor con rsync, que se explica en la guía de respaldo automático con rsync.

Paso 4: Proteger la copia externa frente a borrados

El servidor tiene credenciales para escribir en el repositorio, así que un atacante con root también podría borrar las copias. Para acercarte a la variante 3-2-1-1-0, elige una de estas opciones:

  • Bloqueo de objetos (Object Lock) o versionado en el bucket, si tu proveedor S3 lo ofrece, con una política de retención que impida borrar versiones durante un tiempo. Revisa la documentación del proveedor, porque interactúa con restic forget --prune.
  • Servidor rest-server en modo solo añadir. restic puede usar como destino un servidor propio con rest-server --append-only, que acepta copias nuevas pero no borrados. La limpieza con forget --prune se ejecuta entonces desde una máquina de administración de confianza, no desde el servidor protegido.
  • Una copia periódica desconectada, por ejemplo un disco externo que se conecta solo para actualizarla.

Paso 5: Verificar y probar la restauración

Una copia que nunca se ha restaurado no es una copia fiable. Comprueba la integridad del repositorio, leyendo además una parte de los datos para detectar corrupción en el almacenamiento:

sudo bash -c 'set -a; . /etc/restic/env; restic check --read-data-subset=5%'
...
no errors were found

Lista las instantáneas disponibles:

sudo bash -c 'set -a; . /etc/restic/env; restic snapshots'

Restaura la última instantánea en un directorio temporal, nunca encima de los datos en producción:

sudo bash -c 'set -a; . /etc/restic/env; restic restore latest --target /tmp/restore-test --include /etc/nginx'
sudo diff -r /etc/nginx /tmp/restore-test/etc/nginx && echo "Restauración correcta"

Para las bases de datos, la prueba completa consiste en cargar el volcado en un servidor de pruebas y comprobar que la aplicación arranca con él. Programa estas pruebas en el calendario (por ejemplo, una restauración completa al trimestre) y mide cuánto tardan: ese es tu RTO real.

Cuando termines, borra el directorio de prueba:

sudo rm -rf /tmp/restore-test

Lista de comprobación

Revisa tu estrategia con estas preguntas:

  • ¿Hay al menos una copia fuera del servidor y del proveedor o ubicación principal?
  • ¿Las copias conservan versiones anteriores según la retención definida?
  • ¿Las bases de datos se copian con volcados consistentes y no copiando ficheros en caliente?
  • ¿Las copias externas están cifradas y la contraseña guardada fuera del servidor?
  • ¿Al menos una copia es inmutable o está desconectada?
  • ¿Recibes aviso si un backup falla? Revisa systemctl list-timers y journalctl -u backup-offsite, o integra el estado del servicio en tu monitorización.
  • ¿Has restaurado alguna vez de verdad y sabes cuánto se tarda?

Solución de problemas

Fatal: unable to open config file o error de autenticación S3. El endpoint, el nombre del bucket o las claves de /etc/restic/env son incorrectos, o las variables no se han cargado. Comprueba que usas set -a antes de cargar el fichero en comandos manuales.

unable to create lock in backend: repository is already locked. Otra operación de restic está en marcha o terminó de forma abrupta. Si estás seguro de que no hay ninguna en curso, ejecuta restic unlock.

El servicio falla por mysqldump: Got error: 1045: Access denied. El servicio se ejecuta como root, que se autentica por socket en Ubuntu; si has cambiado la autenticación de root, crea /root/.my.cnf con permisos 600 y las credenciales de un usuario de backup.

Las copias ocupan más de lo esperado. Revisa que excluyes cachés y directorios temporales, y que forget --prune se ejecuta correctamente en el log.

Conclusión

La regla 3-2-1 se resume en tener varias copias, en sistemas independientes y con una fuera de la ubicación principal, pero lo que la hace útil son los objetivos de RPO, RTO y retención y las pruebas de restauración periódicas. Has visto cómo aplicarla con volcados consistentes, restic hacia un almacenamiento externo cifrado y un temporizador systemd. Como siguientes pasos, añade una copia inmutable, configura alertas cuando el servicio de backup falle y documenta el procedimiento de restauración para que cualquier persona del equipo pueda seguirlo.