--- title: "BorgBackup en modo append-only con borgmatic en Ubuntu" description: "Protege tus copias con BorgBackup en modo append-only sobre SSH restringido, automatízalas con borgmatic y systemd, vigila fallos y restaura en Ubuntu 24.04." category: "Herramientas de Servidor" language: es source: https://cubepath.com/es/docs/herramientas-de-servidor/estrategias-avanzadas-de-borgbackup updated: 2026-09-25 --- # BorgBackup en modo append-only con borgmatic en Ubuntu BorgBackup (Borg) es una herramienta de copias de seguridad con deduplicación, compresión y cifrado autenticado. En este tutorial construirás una configuración pensada para resistir un servidor comprometido: el servidor de producción solo puede añadir copias a un repositorio remoto en modo append-only a través de SSH restringido, mientras que la limpieza de copias antiguas se hace desde el servidor de copias. La automatización se hace con borgmatic y systemd en Ubuntu 24.04, con monitorización de fallos y una restauración de prueba. ## Requisitos previos - Un servidor de producción con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath. En esta guía se llama `web01`. - Un servidor de copias con Ubuntu 24.04 y espacio en disco suficiente, accesible por SSH como `backup.your_domain`. - Un usuario no root con privilegios `sudo` en ambos servidores. - Opcional: una cuenta en un servicio de monitorización tipo *dead man's switch* como Healthchecks.io, para recibir avisos si una copia falla o no se ejecuta. Los comandos de esta guía corresponden a Borg 1.2, la versión de Ubuntu 24.04. Borg 2 cambia la sintaxis de varios comandos y no es compatible con repositorios de Borg 1. ## Cómo funciona la protección append-only Si un atacante obtiene root en `web01`, también obtiene la clave SSH y la frase de paso con las que se hacen las copias. Con un acceso normal podría borrar el repositorio remoto antes de cifrar los datos del servidor. La configuración de esta guía lo evita así: | Componente | Qué impide | |---|---| | Comando forzado en `authorized_keys` | La clave de `web01` solo puede ejecutar `borg serve`, sin shell ni otros comandos | | `--restrict-to-path` | Esa clave solo accede al repositorio de `web01` | | `--append-only` | Las operaciones de borrado desde `web01` no eliminan datos: se registran como transacciones nuevas que se pueden deshacer | | `prune` y `compact` en el servidor de copias | Solo el administrador del servidor de copias libera espacio | ## Paso 1: Instalar Borg y borgmatic Instala Borg en los dos servidores. El servidor de copias lo necesita porque el cliente ejecuta `borg serve` en el extremo remoto: ```bash sudo apt update sudo apt install -y borgbackup ``` En `web01` instala también borgmatic, que convierte un archivo YAML en las llamadas a Borg y gestiona retención, verificación y avisos: ```bash sudo apt install -y borgmatic ``` Comprueba las versiones en `web01`: ```bash borg --version borgmatic --version ``` ```output borg 1.2.8 1.8.8 ``` La versión menor puede variar según las actualizaciones de Ubuntu. ## Paso 2: Preparar el usuario de copias en el servidor remoto En `backup.your_domain`, crea un usuario dedicado que solo servirá para recibir copias y el directorio de los repositorios: ```bash sudo adduser --disabled-password --gecos "" borg sudo install -d -o borg -g borg -m 700 /srv/borg sudo install -d -o borg -g borg -m 700 /home/borg/.ssh ``` `--disabled-password` impide iniciar sesión con contraseña; el acceso será solo con la clave que configures a continuación. ## Paso 3: Crear la clave SSH en el servidor de producción En `web01`, genera una clave sin frase de paso para las copias. Se usará desde root, que es quien ejecuta borgmatic: ```bash sudo ssh-keygen -t ed25519 -f /root/.ssh/borg_backup -N "" -C "borg-web01" sudo cat /root/.ssh/borg_backup.pub ``` Copia la línea que empieza por `ssh-ed25519`. ## Paso 4: Restringir la clave a append-only En `backup.your_domain`, edita el archivo de claves autorizadas del usuario `borg`: ```bash sudo nano /home/borg/.ssh/authorized_keys ``` Añade una única línea con las restricciones delante de la clave pública que copiaste: ```text command="borg serve --append-only --restrict-to-path /srv/borg/web01",restrict ssh-ed25519 AAAAC3Nza...tu_clave borg-web01 ``` - `command=` fuerza a que cualquier conexión con esta clave ejecute `borg serve`, ignore lo que pida el cliente. - `restrict` desactiva el reenvío de puertos, agentes y X11, y la asignación de terminal. - `--restrict-to-path` limita el acceso al directorio de este servidor. Si tienes varios servidores de producción, cada uno lleva su propia línea y su propio directorio. Ajusta el propietario y los permisos, que SSH comprueba antes de aceptar la clave: ```bash sudo chown borg:borg /home/borg/.ssh/authorized_keys sudo chmod 600 /home/borg/.ssh/authorized_keys ``` ## Paso 5: Generar la frase de paso En `web01`, crea la frase de paso del repositorio en un archivo legible solo por root: ```bash sudo sh -c 'openssl rand -base64 32 > /root/.borg-passphrase' sudo chmod 600 /root/.borg-passphrase ``` Guarda una copia de esta frase fuera del servidor, por ejemplo en tu gestor de contraseñas. La necesitarás para restaurar desde otra máquina y para limpiar el repositorio desde el servidor de copias. ## Paso 6: Configurar borgmatic Crea el archivo de configuración de borgmatic: ```bash sudo mkdir -p /etc/borgmatic sudo nano /etc/borgmatic/config.yaml ``` ```yaml source_directories: - /etc - /home - /root - /var/www - /var/backups repositories: - path: ssh://borg@backup.your_domain/srv/borg/web01 label: remoto exclude_patterns: - /home/*/.cache - /root/.cache - /var/www/*/node_modules - '*.tmp' exclude_caches: true one_file_system: true archive_name_format: 'web01-{now:%Y-%m-%dT%H:%M:%S}' compression: auto,zstd,6 encryption_passcommand: cat /root/.borg-passphrase ssh_command: ssh -i /root/.ssh/borg_backup -o IdentitiesOnly=yes keep_daily: 7 keep_weekly: 4 keep_monthly: 12 checks: - name: repository frequency: 1 week - name: archives frequency: 2 weeks before_backup: - runuser -u postgres -- pg_dumpall > /var/backups/postgres.sql ``` Qué hace cada bloque: - `source_directories` y `exclude_patterns` definen qué se copia. `exclude_caches` omite directorios con un archivo `CACHEDIR.TAG` y `one_file_system` evita entrar en otros sistemas de archivos montados. - `archive_name_format` pone el nombre del servidor como prefijo; la retención solo se aplica a los archivos con ese prefijo. - `compression: auto,zstd,6` comprime con zstd nivel 6 solo los fragmentos que Borg estima comprimibles, y guarda sin comprimir los que ya lo están (imágenes, vídeos, archivos `.gz`). - `encryption_passcommand` lee la frase de paso de un archivo en lugar de dejarla escrita en el YAML. - `checks` verifica el repositorio cada semana y los archivos cada dos, sin repetirlo en cada ejecución. - `before_backup` ejecuta un volcado de la base de datos antes de la copia. Si no usas PostgreSQL, bórralo o sustitúyelo por el volcado que corresponda; copiar los archivos de una base de datos en marcha genera copias inconsistentes. Valida la sintaxis: ```bash sudo borgmatic config validate ``` ```output All configuration files are valid: /etc/borgmatic/config.yaml ``` ## Paso 7: Inicializar el repositorio Inicializa el repositorio desde `web01`. Se crea a través de la conexión restringida, por lo que la ruta debe coincidir con `--restrict-to-path`: ```bash sudo borgmatic init --encryption repokey-blake2 ``` `repokey-blake2` guarda la clave de cifrado dentro del repositorio, protegida con la frase de paso, y usa BLAKE2b para la autenticación, más rápido que SHA-256 en la mayoría de CPU. Como la clave vive en el repositorio, expórtala y guárdala fuera de ambos servidores: si el archivo de configuración del repositorio se corrompe, sin esta copia no podrías leer los datos aunque conserves la frase de paso. ```bash sudo BORG_PASSCOMMAND="cat /root/.borg-passphrase" BORG_RSH="ssh -i /root/.ssh/borg_backup -o IdentitiesOnly=yes" \ borg key export ssh://borg@backup.your_domain/srv/borg/web01 /root/borg-web01.key ``` Copia `/root/borg-web01.key` a un lugar seguro y bórralo del servidor. ## Paso 8: Ejecutar la primera copia El modo append-only del servidor no bloquea el `prune` del cliente: simplemente lo convierte en una operación que no libera espacio y que el administrador puede revertir. Para que las ejecuciones de `web01` hagan solo lo que tiene sentido, lanza explícitamente las acciones `create` y `check`: ```bash sudo borgmatic create check --verbosity 1 --list --stats ``` ```output remoto: Creating archive ... Archive name: web01-2026-09-25T10:14:02 Original size Compressed size Deduplicated size This archive: 2.03 GB 812.44 MB 790.12 MB All archives: 2.03 GB 812.44 MB 790.12 MB ``` Lista los archivos del repositorio para comprobar que la copia existe: ```bash sudo borgmatic list ``` ```output remoto: Listing archives web01-2026-09-25T10:14:02 Fri, 2026-09-25 10:14:04 [5d0c...] ``` Comprueba ahora que la restricción funciona. Intenta abrir una shell con la clave de copias: ```bash sudo ssh -i /root/.ssh/borg_backup borg@backup.your_domain ``` La conexión no devuelve una shell: `borg serve` se queda esperando el protocolo de Borg. Pulsa `Ctrl+C` para salir. ## Paso 9: Programar las copias con systemd Crea un servicio que ejecute borgmatic con prioridad baja de CPU y disco: ```bash sudo nano /etc/systemd/system/borgmatic-web01.service ``` ```ini [Unit] Description=Copia de seguridad con borgmatic Wants=network-online.target After=network-online.target [Service] Type=oneshot Nice=19 IOSchedulingClass=idle ExecStart=/usr/bin/borgmatic create check --verbosity 1 --stats ``` Y el timer diario: ```bash sudo nano /etc/systemd/system/borgmatic-web01.timer ``` ```ini [Unit] Description=Copia diaria con borgmatic [Timer] OnCalendar=*-*-* 03:00:00 RandomizedDelaySec=15min Persistent=true [Install] WantedBy=timers.target ``` Actívalo y comprueba la próxima ejecución: ```bash sudo systemctl daemon-reload sudo systemctl enable --now borgmatic-web01.timer systemctl list-timers borgmatic-web01.timer ``` Para ver el resultado de la última ejecución usa `sudo journalctl -u borgmatic-web01.service -n 50`. Si la salida de `systemctl list-timers 'borgmatic*'` muestra además un `borgmatic.timer` activo instalado por el paquete, desactívalo con `sudo systemctl disable --now borgmatic.timer`, ya que ejecutaría todas las acciones de borgmatic, incluido `prune`. ## Paso 10: Recibir avisos si una copia falla Un fallo silencioso es el problema más común de las copias automatizadas. borgmatic puede notificar a Healthchecks.io al empezar, al terminar y al fallar; si una ejecución no llega a producirse (servidor apagado, timer desactivado), Healthchecks también avisa al no recibir la señal a tiempo. Crea un check en el servicio con un periodo de un día y añade su URL al final de `/etc/borgmatic/config.yaml`: ```yaml healthchecks: ping_url: https://hc-ping.com/your-check-uuid ``` Valida de nuevo la configuración y lanza una ejecución manual: ```bash sudo borgmatic config validate sudo systemctl start borgmatic-web01.service ``` En el panel de Healthchecks el check pasa a estado *up* y muestra el log de borgmatic de esa ejecución. ## Paso 11: Aplicar la retención desde el servidor de copias La limpieza de archivos antiguos se hace en `backup.your_domain`, accediendo al repositorio directamente en disco y no a través de la clave restringida. Así, aunque `web01` esté comprometido, no puede provocarla. Antes de hacer `prune`, revisa la lista de archivos. Si un atacante hubiera enviado borrados desde `web01`, el modo append-only los habría registrado como transacciones; al compactar en el servidor esos borrados se harían efectivos. Si detectas archivos que faltan sin explicación, no compactes y consulta la sección sobre append-only de la documentación de Borg para revertir las transacciones. En el servidor de copias, trabaja como el usuario `borg` y pide la frase de paso de forma interactiva, para no guardarla en este servidor: ```bash sudo -u borg -i borg list /srv/borg/web01 ``` Comprueba también que el repositorio no tiene activado el modo append-only en su propia configuración (la protección se aplica solo en la conexión SSH). El valor debe ser `0`; si es `1`, cámbialo con `borg config /srv/borg/web01 append_only 0` para poder liberar espacio: ```bash borg config /srv/borg/web01 append_only ``` Simula la retención para ver qué se borraría: ```bash borg prune --list --dry-run \ --glob-archives 'web01-*' \ --keep-daily 7 --keep-weekly 4 --keep-monthly 12 \ /srv/borg/web01 ``` ```output Keeping archive (rule: daily #1): web01-2026-09-25T03:04:11 Fri, 2026-09-25 03:04:13 [..] Would prune: web01-2026-08-01T03:02:45 Sat, 2026-08-01 03:02:47 [..] ``` Si la lista es correcta, ejecuta el `prune` real y libera el espacio con `compact`, que en Borg 1.2 es un paso separado: ```bash borg prune --list \ --glob-archives 'web01-*' \ --keep-daily 7 --keep-weekly 4 --keep-monthly 12 \ /srv/borg/web01 borg compact /srv/borg/web01 exit ``` Usa los mismos valores `keep_*` que en borgmatic. Hazlo con la frecuencia que te permita el disco; una vez al mes suele bastar con la retención de esta guía. ## Paso 12: Restaurar archivos Prueba la restauración desde `web01`. Para recuperar un directorio concreto, extráelo en una ruta temporal: ```bash sudo mkdir -p /tmp/restore sudo borgmatic extract --archive latest --path etc/nginx --destination /tmp/restore ``` Las rutas dentro del archivo no llevan la barra inicial y `--destination` evita sobrescribir los archivos en uso. Compara con el original: ```bash sudo diff -r /etc/nginx /tmp/restore/etc/nginx && echo "Restauración correcta" ``` ```output Restauración correcta ``` Para restaurar un archivo antiguo, usa el nombre del archivo que aparece en `borgmatic list` en lugar de `latest`. Cuando termines, borra la ruta temporal: ```bash sudo rm -rf /tmp/restore ``` Para recuperar un servidor completo en una máquina nueva, instala Borg, copia la clave SSH y la frase de paso, e importa la clave exportada en el paso 7 si el repositorio la hubiera perdido (`borg key import`). A partir de ahí el procedimiento es el mismo `extract`. ## Solución de problemas **`Repository ... does not exist` o `Permission denied` en el primer `init`.** La ruta de `repositories` no coincide con `--restrict-to-path`, o el directorio `/srv/borg` no pertenece al usuario `borg`. **`Failed to create/acquire the lock`.** Una ejecución anterior se interrumpió. Comprueba que no hay otra copia en marcha (`pgrep -a borg` en ambos servidores) y elimina el bloqueo con `sudo borgmatic break-lock`. **`Remote: borg: command not found`.** Borg no está instalado en el servidor de copias o no está en el `PATH` del usuario `borg`. Instálalo con `apt` o usa la ruta completa en el comando forzado de `authorized_keys`. **El espacio en el servidor de copias no baja tras `prune`.** Falta ejecutar `borg compact`. Con el modo append-only, el espacio solo se libera al compactar en el propio servidor de copias. **`passphrase supplied in BORG_PASSPHRASE, by BORG_PASSCOMMAND or via BORG_PASSPHRASE_FD is incorrect`.** El archivo `/root/.borg-passphrase` no coincide con la frase usada en `init`. Recupérala de tu copia externa. ## Conclusión Tienes copias diarias cifradas que el servidor de producción puede crear pero no destruir, con verificación periódica, avisos cuando algo falla, retención aplicada desde el servidor de copias y una restauración comprobada. Como siguientes pasos, añade un segundo repositorio en otra ubicación a la lista `repositories` de borgmatic, programa en tu calendario la limpieza mensual y repite la prueba de restauración en un servidor limpio al menos una vez por trimestre.