--- title: "Configuración avanzada de Restic en Ubuntu 24.04" description: "Configura Restic en Ubuntu 24.04 con dos repositorios (S3 y SFTP), exclusiones, retención, límite de ancho de banda, timers de systemd y restauración de prueba." category: "Herramientas de Servidor" language: es source: https://cubepath.com/es/docs/herramientas-de-servidor/configuracion-avanzada-de-restic-backup updated: 2026-09-25 --- # Configuración avanzada de Restic en Ubuntu 24.04 Restic es una herramienta de copias de seguridad que cifra y deduplica los datos antes de enviarlos a un repositorio local, SFTP o compatible con S3. En este tutorial montarás una configuración de producción en Ubuntu 24.04: dos repositorios independientes (uno en almacenamiento S3 y otro en un servidor por SFTP) para cumplir la regla 3-2-1, exclusiones, política de retención, límite de ancho de banda, ejecución diaria con timers de systemd, aviso en caso de fallo y una restauración de prueba. ## Requisitos previos - Un servidor con Ubuntu 24.04 LTS del que quieres hacer copias, por ejemplo un VPS de CubePath. En esta guía se llama `web01`. - Un usuario no root con privilegios `sudo`. Restic se ejecutará como root para poder leer todos los archivos. - Un bucket en un servicio compatible con S3 con su endpoint, clave de acceso y clave secreta. - Un segundo servidor accesible por SSH con espacio libre para el repositorio SFTP, en esta guía `backup.your_domain`, con un usuario `restic`. Sustituye `your_domain`, el nombre del bucket y las credenciales de ejemplo por los tuyos. ## Paso 1: Instalar Restic Restic está en los repositorios de Ubuntu: ```bash sudo apt update sudo apt install -y restic ``` Comprueba la versión: ```bash restic version ``` ```output restic 0.16.4 compiled with go1.22.2 on linux/amd64 ``` La versión 0.16 incluye todo lo que usa esta guía, incluida la compresión. El paquete de Ubuntu desactiva `restic self-update`; si necesitas una versión más reciente, descarga el binario desde la página de publicaciones de Restic en GitHub y colócalo en `/usr/local/bin`. ## Paso 2: Guardar la contraseña y las credenciales Restic cifra cada repositorio con una contraseña. Si la pierdes, los datos son irrecuperables, así que guárdala también fuera del servidor, por ejemplo en tu gestor de contraseñas. Crea un directorio accesible solo por root y genera una contraseña aleatoria en un archivo: ```bash sudo install -d -m 700 /etc/restic sudo sh -c 'openssl rand -base64 32 > /etc/restic/password' sudo chmod 600 /etc/restic/password ``` Crea un archivo de entorno para el repositorio S3: ```bash sudo nano /etc/restic/s3.env ``` ```ini RESTIC_REPOSITORY=s3:https://s3.your_provider.com/your_bucket/web01 RESTIC_PASSWORD_FILE=/etc/restic/password AWS_ACCESS_KEY_ID=your_access_key AWS_SECRET_ACCESS_KEY=your_secret_key ``` El formato `s3:https://endpoint/bucket/ruta` funciona con AWS y con cualquier servicio compatible con S3; la ruta final permite guardar varios servidores en el mismo bucket. Crea el archivo del repositorio SFTP: ```bash sudo nano /etc/restic/sftp.env ``` ```ini RESTIC_REPOSITORY=sftp:restic@backup.your_domain:/srv/restic/web01 RESTIC_PASSWORD_FILE=/etc/restic/password ``` Protege ambos archivos: ```bash sudo chmod 600 /etc/restic/s3.env /etc/restic/sftp.env ``` Usar `RESTIC_PASSWORD_FILE` en lugar de `RESTIC_PASSWORD` evita que la contraseña aparezca en el entorno de cada proceso. ## Paso 3: Preparar el acceso SFTP Restic usa el cliente SSH del sistema, y como las copias se ejecutan como root, la clave debe estar en la cuenta de root. Genera una clave sin frase de paso dedicada a las copias: ```bash sudo ssh-keygen -t ed25519 -f /root/.ssh/restic_backup -N "" -C "restic-web01" ``` Indica a SSH que use esa clave para el servidor de copias: ```bash sudo nano /root/.ssh/config ``` ```text Host backup.your_domain User restic IdentityFile /root/.ssh/restic_backup IdentitiesOnly yes ``` Muestra la clave pública y añádela a `~/.ssh/authorized_keys` del usuario `restic` en el servidor de copias: ```bash sudo cat /root/.ssh/restic_backup.pub ``` En el servidor de copias, crea el directorio de destino como el usuario `restic`: ```bash mkdir -p /srv/restic ``` De vuelta en `web01`, comprueba la conexión. La primera vez acepta la huella del servidor: ```bash sudo sftp backup.your_domain <<< 'ls /srv/restic' ``` Si el comando lista el directorio sin pedir contraseña, el acceso está listo. ## Paso 4: Inicializar los repositorios Los archivos de entorno se cargan con `set -a`, que exporta cada variable definida. Abre una shell de root para los comandos manuales de esta guía: ```bash sudo -i ``` Inicializa el repositorio S3: ```bash set -a; . /etc/restic/s3.env; set +a restic init ``` ```output created restic repository 3a1f9c0b2e at s3:https://s3.your_provider.com/your_bucket/web01 ``` Inicializa el repositorio SFTP en la misma shell. Las variables del segundo archivo sustituyen a las del primero: ```bash set -a; . /etc/restic/sftp.env; set +a restic init ``` Ambos repositorios usan la misma contraseña para simplificar la gestión, pero son independientes: tienen claves de cifrado distintas y un fallo en uno no afecta al otro. ## Paso 5: Definir qué se copia y qué no Guarda la lista de rutas y de exclusiones en archivos para que el script, los comandos manuales y cualquier cambio futuro usen la misma definición: ```bash nano /etc/restic/paths.txt ``` ```text /etc /home /root /var/www /var/backups ``` ```bash nano /etc/restic/excludes.txt ``` ```text /home/*/.cache /root/.cache /var/www/*/node_modules /var/www/*/.next *.tmp *.swp ``` No copies los archivos de datos de una base de datos en ejecución (`/var/lib/mysql`, `/var/lib/postgresql`): la copia sería inconsistente. Exporta la base de datos a `/var/backups` con `mysqldump` o `pg_dump` antes de la copia y deja que Restic guarde ese volcado. Haz una primera copia manual al repositorio SFTP, que todavía está cargado en tu shell: ```bash restic backup \ --files-from /etc/restic/paths.txt \ --exclude-file /etc/restic/excludes.txt \ --exclude-caches \ --one-file-system \ --tag diario ``` ```output Files: 48213 new, 0 changed, 0 unmodified Dirs: 6120 new, 0 changed, 0 unmodified Added to the repository: 1.215 GiB (512.304 MiB stored) processed 48213 files, 1.873 GiB in 0:41 snapshot 9b2e7c1d saved ``` `--exclude-caches` omite los directorios marcados con un archivo `CACHEDIR.TAG` y `--one-file-system` evita entrar en otros sistemas de archivos montados dentro de las rutas, como `/proc` o un disco de red. Lista las instantáneas: ```bash restic snapshots ``` ```output ID Time Host Tags Paths ------------------------------------------------------------------ 9b2e7c1d 2026-09-25 10:12:03 web01 diario /etc /home /root /var/backups /var/www ------------------------------------------------------------------ 1 snapshots ``` ## Paso 6: Probar la política de retención `restic forget` decide qué instantáneas conservar y `--prune` elimina los datos que ya no usa ninguna. Antes de automatizarlo, simula la política con `--dry-run` para ver qué se borraría: ```bash restic forget \ --tag diario \ --keep-daily 7 \ --keep-weekly 4 \ --keep-monthly 12 \ --dry-run ``` ```output Applying Policy: keep 7 daily, 4 weekly, 12 monthly snapshots keep 1 snapshots: ID Time Host Tags Reasons Paths ... ``` Con esta política conservas una copia por día durante una semana, una por semana durante un mes y una por mes durante un año. Las opciones `--keep-*` se combinan: una misma instantánea puede cumplir varias reglas y solo se borra si no cumple ninguna. Por defecto Restic agrupa por host y rutas, de modo que la retención de un servidor no afecta a otro que comparta repositorio. El `prune` tiene que leer el índice del repositorio y, en S3, cada operación cuesta tiempo y peticiones. Por eso en el script se ejecuta con la copia diaria, pero la verificación completa de integridad se programa aparte. Sal de la shell de root: ```bash exit ``` ## Paso 7: Crear el script de copia El script recorre los dos repositorios, hace la copia y aplica la retención en cada uno. Si un repositorio falla, sigue con el otro y termina con error al final para que systemd lo registre. ```bash sudo nano /usr/local/sbin/restic-backup ``` ```bash #!/usr/bin/env bash set -euo pipefail REPOS=(/etc/restic/s3.env /etc/restic/sftp.env) status=0 for env_file in "${REPOS[@]}"; do echo "==> Copia en ${env_file}" if ! ( set -a . "$env_file" set +a restic backup \ --files-from /etc/restic/paths.txt \ --exclude-file /etc/restic/excludes.txt \ --exclude-caches \ --one-file-system \ --tag diario \ --limit-upload "${RESTIC_LIMIT_UPLOAD:-0}" restic forget \ --tag diario \ --keep-daily 7 \ --keep-weekly 4 \ --keep-monthly 12 \ --prune ); then echo "ERROR: fallo en ${env_file}" >&2 status=1 fi done exit "$status" ``` Cada repositorio se procesa en una subshell `( ... )`, así las variables de uno no se mezclan con las del siguiente. `--limit-upload` limita la subida en KiB/s; con el valor `0` no hay límite, y el valor real se define en la unidad de systemd. Hazlo ejecutable: ```bash sudo chmod 750 /usr/local/sbin/restic-backup ``` ## Paso 8: Programar la copia con un timer de systemd Un timer de systemd registra cada ejecución en el journal, evita que se solapen dos ejecuciones y permite bajar la prioridad del proceso. Crea el servicio: ```bash sudo nano /etc/systemd/system/restic-backup.service ``` ```ini [Unit] Description=Copia de seguridad con Restic Wants=network-online.target After=network-online.target OnFailure=restic-notify@%n.service [Service] Type=oneshot Environment=RESTIC_CACHE_DIR=/var/cache/restic Environment=RESTIC_LIMIT_UPLOAD=20480 Nice=19 IOSchedulingClass=idle ExecStart=/usr/local/sbin/restic-backup ``` `RESTIC_LIMIT_UPLOAD=20480` limita la subida a 20 MiB/s para no saturar el enlace del servidor; ajústalo a tu caso. `Nice=19` e `IOSchedulingClass=idle` hacen que la copia ceda CPU y disco a los servicios en producción. Crea el timer: ```bash sudo nano /etc/systemd/system/restic-backup.timer ``` ```ini [Unit] Description=Copia diaria con Restic [Timer] OnCalendar=*-*-* 02:30:00 RandomizedDelaySec=15min Persistent=true [Install] WantedBy=timers.target ``` `Persistent=true` ejecuta la copia al arrancar si el servidor estaba apagado a la hora programada. `RandomizedDelaySec` reparte la carga cuando varios servidores escriben en el mismo almacenamiento. ## Paso 9: Recibir un aviso cuando falla La línea `OnFailure=` del servicio lanza otra unidad si la copia termina con error. Crea esa unidad como plantilla, de modo que reciba el nombre del servicio que falló. Este ejemplo envía el aviso a un tema de [ntfy](https://ntfy.sh); sustituye la URL por la de tu servidor o tema: ```bash sudo nano /etc/systemd/system/restic-notify@.service ``` ```ini [Unit] Description=Aviso de fallo en %i [Service] Type=oneshot ExecStart=/usr/bin/curl -fsS -m 10 -H "Title: Fallo en %i (%H)" -H "Priority: high" -d "Revisa: journalctl -u %i" https://ntfy.sh/your_topic ``` `%i` es el nombre del servicio que falló y `%H` el nombre del host. Recarga systemd y activa el timer: ```bash sudo systemctl daemon-reload sudo systemctl enable --now restic-backup.timer ``` Lanza una ejecución manual para comprobar que todo funciona sin esperar a la noche: ```bash sudo systemctl start restic-backup.service sudo journalctl -u restic-backup.service -n 30 --no-pager ``` Deberías ver las dos secciones `==> Copia en ...`, cada una con su línea `snapshot ... saved`. Comprueba la próxima ejecución programada: ```bash systemctl list-timers restic-backup.timer ``` ```output NEXT LEFT LAST PASSED UNIT ACTIVATES Fri 2026-09-26 02:38:12 UTC 16h left Thu 2026-09-25 10:20:41 UTC 1min ago restic-backup.timer restic-backup.service ``` ## Paso 10: Verificar la integridad cada semana `restic check` comprueba la estructura del repositorio. Con `--read-data-subset` además descarga y verifica una parte de los datos; leer un porcentaje distinto cada semana detecta corrupción en el almacenamiento sin descargar todo el repositorio de golpe. Crea el servicio de verificación: ```bash sudo nano /etc/systemd/system/restic-check.service ``` ```ini [Unit] Description=Verificación de repositorios Restic Wants=network-online.target After=network-online.target OnFailure=restic-notify@%n.service [Service] Type=oneshot Environment=RESTIC_CACHE_DIR=/var/cache/restic Nice=19 IOSchedulingClass=idle ExecStart=/bin/bash -c 'set -euo pipefail; for f in /etc/restic/s3.env /etc/restic/sftp.env; do (set -a; . "$f"; set +a; restic check --read-data-subset=10%%); done' ``` En las unidades de systemd el carácter `%` se escribe `%%`. Crea el timer semanal: ```bash sudo nano /etc/systemd/system/restic-check.timer ``` ```ini [Unit] Description=Verificación semanal de Restic [Timer] OnCalendar=Sun *-*-* 05:00:00 Persistent=true [Install] WantedBy=timers.target ``` Actívalo y ejecútalo una vez: ```bash sudo systemctl daemon-reload sudo systemctl enable --now restic-check.timer sudo systemctl start restic-check.service sudo journalctl -u restic-check.service -n 20 --no-pager ``` ```output using temporary cache in /var/cache/restic check snapshots, trees and blobs read 10.0% of data packs no errors were found ``` ## Paso 11: Probar una restauración Una copia que nunca se ha restaurado no está probada. Abre una shell de root y carga uno de los repositorios: ```bash sudo -i set -a; . /etc/restic/sftp.env; set +a ``` Busca en qué instantáneas está un archivo: ```bash restic find /etc/nginx/nginx.conf ``` Restaura solo ese directorio de la última instantánea en una ruta temporal, sin tocar los archivos en uso: ```bash restic restore latest --target /tmp/restore --include /etc/nginx ``` Compara el resultado con el original: ```bash diff -r /etc/nginx /tmp/restore/etc/nginx && echo "Restauración correcta" ``` ```output Restauración correcta ``` Para restauraciones desde S3 de mucho volumen, añade `--limit-download` (en KiB/s) si no quieres saturar el enlace. Cuando termines, borra la ruta temporal y sal de la shell de root: ```bash rm -rf /tmp/restore exit ``` ## Solución de problemas **`unable to create lock in backend: repository is already locked`.** Una ejecución anterior se interrumpió y dejó un bloqueo. Comprueba que no hay ningún proceso de Restic en marcha (`pgrep -a restic`) y elimina los bloqueos obsoletos con `restic unlock`. **`Fatal: wrong password or no key found`.** El archivo `/etc/restic/password` no coincide con el que se usó en `restic init`. Recupera la contraseña de tu copia externa; sin ella no es posible leer el repositorio. **`restic check` informa de errores en el índice.** Reconstrúyelo con `restic repair index` y vuelve a ejecutar la verificación. **La copia SFTP pide contraseña o falla con `Permission denied`.** Restic se ejecuta como root, así que la clave y `~/.ssh/config` deben estar en `/root/.ssh`. Prueba con `sudo sftp backup.your_domain`. **Las copias tardan mucho en S3.** Asegúrate de que `RESTIC_CACHE_DIR` apunta a un directorio persistente; sin caché local, Restic descarga los metadatos del repositorio en cada ejecución. ## Conclusión Tienes copias diarias cifradas en dos repositorios independientes, con retención automática, prioridad baja para no afectar a producción, verificación semanal de integridad, avisos de fallo y una restauración probada. Como siguientes pasos, guarda la contraseña del repositorio fuera del servidor, añade un volcado de tus bases de datos antes de la copia y repite la prueba de restauración de forma periódica, idealmente en un servidor distinto.