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
sudoen 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:
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:
sudo apt install -y borgmatic
Comprueba las versiones en web01:
borg --version
borgmatic --version
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:
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:
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:
sudo nano /home/borg/.ssh/authorized_keys
Añade una única línea con las restricciones delante de la clave pública que copiaste:
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 ejecuteborg serve, ignore lo que pida el cliente.restrictdesactiva el reenvío de puertos, agentes y X11, y la asignación de terminal.--restrict-to-pathlimita 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:
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:
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:
sudo mkdir -p /etc/borgmatic
sudo nano /etc/borgmatic/config.yaml
source_directories:
- /etc
- /home
- /root
- /var/www
- /var/backups
repositories:
- path: ssh://[email protected]_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_directoriesyexclude_patternsdefinen qué se copia.exclude_cachesomite directorios con un archivoCACHEDIR.TAGyone_file_systemevita entrar en otros sistemas de archivos montados.archive_name_formatpone el nombre del servidor como prefijo; la retención solo se aplica a los archivos con ese prefijo.compression: auto,zstd,6comprime 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_passcommandlee la frase de paso de un archivo en lugar de dejarla escrita en el YAML.checksverifica el repositorio cada semana y los archivos cada dos, sin repetirlo en cada ejecución.before_backupejecuta 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:
sudo borgmatic config validate
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:
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.
sudo BORG_PASSCOMMAND="cat /root/.borg-passphrase" BORG_RSH="ssh -i /root/.ssh/borg_backup -o IdentitiesOnly=yes" \
borg key export ssh://[email protected]_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:
sudo borgmatic create check --verbosity 1 --list --stats
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:
sudo borgmatic list
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:
sudo ssh -i /root/.ssh/borg_backup [email protected]_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:
sudo nano /etc/systemd/system/borgmatic-web01.service
[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:
sudo nano /etc/systemd/system/borgmatic-web01.timer
[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:
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:
healthchecks:
ping_url: https://hc-ping.com/your-check-uuid
Valida de nuevo la configuración y lanza una ejecución manual:
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:
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:
borg config /srv/borg/web01 append_only
Simula la retención para ver qué se borraría:
borg prune --list --dry-run \
--glob-archives 'web01-*' \
--keep-daily 7 --keep-weekly 4 --keep-monthly 12 \
/srv/borg/web01
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:
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:
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:
sudo diff -r /etc/nginx /tmp/restore/etc/nginx && echo "Restauración correcta"
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:
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.
