Las copias de seguridad son la disciplina donde más se aprende por las malas y menos se escribe sobre ello hasta que duele. Después de varios incidentes en los que la copia estaba pero no era restaurable, de otros donde el destino era el mismo servidor que se quemó, y de algún descubrimiento tardío de que el cifrado no estaba activado, he acabado con una rutina basada en restic que cubre lo básico sin pretender ser ingeniería aeroespacial. Esta entrada documenta cómo instalarla en Debian, configurar un repositorio cifrado en almacenamiento S3 compatible, automatizar copias diarias con systemd y, crucialmente, verificar que la restauración funciona antes de necesitarla.
Por qué restic
Las opciones en el espacio de copias de seguridad abiertas y maduras son varias: restic, borg, duplicity, rclone con cifrado y, más reciente, kopia. Todas resuelven la parte difícil (cifrado, deduplicación, copias incrementales), pero tienen filosofías distintas. La razón por la que uso restic en la mayoría de casos es la combinación de tres propiedades: escribe en cualquier repositorio S3 compatible sin capas extra, tiene un modelo de cifrado simple y verificable, y su formato de repositorio es estable desde hace años con alta confianza en la comunidad. Borg es excelente pero exige un servicio escuchando en el destino; duplicity es más antiguo y trabaja con ficheros de parche encadenados que complican restauraciones parciales; kopia es moderno pero aún rotar piezas.
restic cifra todo en el cliente con AES-256 antes de enviarlo al repositorio. El operador del almacenamiento no ve nada, salvo tamaños y metadatos opacos. Deduplica a nivel de bloque variable, de forma que un fichero modificado solo transmite los bloques cambiados, y almacena el resultado como objetos de tamaño manejable. Un repositorio restic tiene todos los datos que necesita para reconstruirse, sin servidor en el lado remoto que mantenga estado.
Instalación en Debian 13
La instalación en Debian es directa. El paquete del repositorio oficial suele ir un par de versiones por detrás, así que para producción prefiero instalar desde los binarios oficiales del proyecto, que salen firmados y son fáciles de verificar. En 2025 la versión estable es 0.18. El flujo mínimo descarga el binario comprimido y el fichero de sumas, verifica con sha256sum, descomprime con bunzip2 y lo instala con install -m 0755 en /usr/local/bin/restic. Alternativamente se puede usar apt install restic y aceptar la versión del repositorio, que para la mayoría de casos sirve. La diferencia práctica son correcciones de errores y algunas mejoras de rendimiento en versiones recientes.
Configurar un repositorio en S3 compatible
restic trabaja con muchos tipos de repositorio: directorio local, SFTP, S3, Backblaze B2, Azure, Google Cloud Storage. El caso que cubro aquí es un repositorio en un servicio S3 compatible, que es el patrón que mejor separa datos de copias del servidor protegido. Hetzner Object Storage funciona bien, igual que Backblaze B2, Wasabi o un bucket en AWS. Lo primero es generar credenciales con permiso mínimo: solo crear objetos, listarlos y leerlos en el bucket destino. No hace falta permiso de borrado porque restic gestiona sus propios ciclos de vida y los borrados pueden hacerse con una credencial distinta para limitar el radio de un compromiso.
# Instalación, repositorio y primera copia
VERSION=0.18.0
curl -LO "https://github.com/restic/restic/releases/download/v${VERSION}/restic_${VERSION}_linux_amd64.bz2"
curl -LO "https://github.com/restic/restic/releases/download/v${VERSION}/SHA256SUMS"
grep "restic_${VERSION}_linux_amd64.bz2" SHA256SUMS | sha256sum -c -
bunzip2 restic_${VERSION}_linux_amd64.bz2
sudo install -m 0755 restic_${VERSION}_linux_amd64 /usr/local/bin/restic
# Variables de entorno y contraseña
export AWS_ACCESS_KEY_ID="..."
export AWS_SECRET_ACCESS_KEY="..."
export RESTIC_REPOSITORY="s3:https://fsn1.your-objectstorage.com/mi-bucket-backup"
export RESTIC_PASSWORD_FILE=/etc/restic-password
openssl rand -base64 48 | sudo tee /etc/restic-password > /dev/null
sudo chmod 400 /etc/restic-password
# Inicialización y primera copia
restic init
restic backup --tag primera --exclude-file /etc/restic-excludes /home /etc /var/lib/docker/volumes /opt
# Restauración de prueba (parte del script semanal)
TEMPDIR=$(mktemp -d)
restic restore latest --target "$TEMPDIR" --include /etc/hostname
test "$(cat $TEMPDIR/etc/hostname)" = "$(hostname)" && echo "restore_ok" || echo "restore_fail"
rm -rf "$TEMPDIR"
La contraseña guardada en /etc/restic-password es lo único que se necesita para descifrar el repositorio. Guardarla además en una ubicación secundaria fuera del servidor es una parte fundamental de la estrategia: si se pierde la contraseña, se pierde el repositorio entero aunque los datos sigan en el bucket. Un gestor de contraseñas, una caja fuerte física con el valor impreso, otro servidor que la replique. La opción concreta importa menos que tener al menos dos copias independientes.
Primera copia de seguridad
Lo que aparece en el fichero de exclusiones merece cuidado. Hay directorios que no conviene incluir: /tmp, cualquier sitio donde haya cachés grandes o sockets Unix, las rutas de los propios datos del gestor de contenedores si ya cubres sus volúmenes, y ficheros sensibles no cifrados que no deben viajar al repositorio aunque restic los cifre. Revisar este fichero periódicamente evita copias que crecen sin motivo. La primera copia tarda porque transmite todo. Las siguientes son mucho más rápidas porque restic deduplica contra lo ya presente: solo viajan los bloques nuevos. En mi experiencia una copia incremental sobre un servidor con decenas de gigas de datos tarda entre treinta segundos y dos minutos, dominado por la enumeración de ficheros más que por la red.
Automatización con systemd
El patrón que uso es un par timer + service, porque da mejor observabilidad y control que cron. El servicio declara Type=oneshot, lee un EnvironmentFile=/etc/restic/restic.env con las credenciales y la ruta del repositorio, y ejecuta un script /usr/local/bin/restic-backup.sh que envuelve la copia. El timer acompaña al servicio con OnCalendar=*-*-* 02:00:00, un RandomizedDelaySec=30m para evitar tormentas, y Persistent=true para que recupere copias perdidas si el servidor estuvo apagado. Las unidades se instalan en /etc/systemd/system/restic-backup.service y .timer, y se activan con systemctl enable --now restic-backup.timer.
El script hace la copia, aplica forget con la política de retención (mantener los últimos siete diarios, cuatro semanales, doce mensuales, por ejemplo), ejecuta prune para liberar espacio, y escribe un fichero de métricas en /var/lib/node-exporter/textfile/restic.prom con éxito, duración y tamaño. Esas métricas luego se vigilan con reglas de alerta que avisan si la copia falla o si no se ha ejecutado en más de 36 horas. El segundo tipo de alerta, el de ausencia de métrica, atrapa fallos silenciosos donde el script ni siquiera llega a escribir resultado.
Verificación de restauración
La parte que se olvida con más frecuencia y la que duele más cuando toca. Un repositorio al que nunca se ha hecho restore no es una copia de seguridad, es una ilusión. La rutina que mantengo es semanal: un timer distinto dispara un script que elige un snapshot reciente, extrae un subconjunto conocido a un directorio temporal, compara contra una instantánea de referencia y reporta el resultado. Si la verificación falla, me llega una alerta inmediata. El fragmento de restore del bloque anterior ilustra la lógica básica; en el sistema real se compara contra más de un fichero y se exportan métricas con el resultado.
Además del restore de muestra, una vez por semana ejecuto restic check --read-data-subset=5% que verifica integridad de una fracción del repositorio leyendo y comparando contra los hashes almacenados. En seis meses he detectado dos fallos: uno fue una credencial expirada que el script no reportaba como error, otro fue un bloque corrompido que el proveedor de almacenamiento repuso tras abrir incidencia. Sin la verificación semanal ninguno se habría detectado hasta el desastre.
Cómo pensar la decisión
Mi lectura tras varios años operando con restic es que resuelve la parte técnica de las copias de seguridad con elegancia y deja al operador concentrarse en la parte difícil, que es la operacional: dónde se guarda la contraseña, quién tiene acceso, qué pasa si el proveedor de almacenamiento desaparece, con qué frecuencia se verifica la restauración, cuántos días de histórico se mantienen. Esa parte no la resuelve ninguna herramienta, y un repositorio cifrado sin plan de recuperación es apenas menos frágil que no tener copia.
La propuesta mínima razonable para un servidor en producción es esta: restic instalado desde binarios verificados, repositorio en un proveedor S3 independiente del servidor, contraseña replicada fuera del servidor en al menos dos sitios, copia diaria por systemd con política de retención, restauración de muestra semanal y alerta si algo de esto falla o deja de reportar métricas. Todo eso se monta en una tarde la primera vez, en quince minutos a partir de la segunda, y evita la clase de desastre que acaba carreras. El tiempo dedicado en frío es trivial comparado con el que se ahorra cuando algo sale mal, y ojalá no haga falta, pero cuando haga falta, agradecerás haberlo montado antes.