BorgBackup (Borg) es una herramienta de copias de seguridad que divide los archivos en fragmentos, guarda cada fragmento una sola vez (deduplicación), los comprime y los cifra antes de enviarlos al repositorio. Así, copiar un servidor cada día apenas ocupa algo más que los cambios de ese día, y el servidor de copias no puede leer los datos. En este tutorial configurarás Borg en Ubuntu 24.04 para enviar copias cifradas a un servidor remoto por SSH, las automatizarás con un timer de systemd, aplicarás una política de retención y restaurarás archivos.
Requisitos previos
Para seguir esta guía necesitas:
- Dos servidores con Ubuntu 24.04 LTS, por ejemplo dos VPS de CubePath:
- El servidor a respaldar (en esta guía,
web01). - El servidor de copias, con espacio suficiente para el repositorio. Idealmente en otra ubicación o centro de datos.
- El servidor a respaldar (en esta guía,
- Un usuario no root con privilegios
sudoen ambos. - Conectividad SSH desde el servidor a respaldar hacia el servidor de copias.
En los ejemplos, backup_server_ip es la IP del servidor de copias.
Cómo organiza Borg las copias
Conviene tener claros tres conceptos antes de empezar:
- Repositorio: el directorio que contiene todos los datos deduplicados y cifrados. Normalmente se usa un repositorio por servidor respaldado.
- Archivo (archive): cada copia que haces con
borg create. Tiene un nombre, por ejemploweb01-2026-09-25T02:00, y contiene la vista completa de los directorios copiados en ese momento. - Clave y frase de paso: con el modo
repokey, la clave de cifrado se guarda dentro del repositorio, protegida por una frase de paso. Necesitas ambas para restaurar. Si pierdes la frase de paso, los datos son irrecuperables.
Paso 1: Instalar BorgBackup en ambos servidores
Borg debe estar instalado en los dos servidores, porque en el servidor de copias se ejecuta borg serve para recibir los datos. Ejecuta en ambos:
sudo apt update
sudo apt install borgbackup
Comprueba la versión:
borg --version
borg 1.2.8
Usa la misma versión principal (1.2.x) en ambos servidores. Los comandos de esta guía son para Borg 1.2.
Paso 2: Preparar el servidor de copias
En el servidor de copias, crea un usuario de sistema borg sin contraseña, que solo servirá para recibir copias, y el directorio de los repositorios:
sudo adduser --system --group --shell /bin/bash --home /srv/borg borg
sudo install -d -m 700 -o borg -g borg /srv/borg/.ssh
Comprueba que el directorio pertenece al nuevo usuario:
ls -ld /srv/borg /srv/borg/.ssh
En ambas líneas deben aparecer borg borg como propietario y grupo, y drwx------ en .ssh.
Paso 3: Crear la clave SSH del servidor a respaldar
Las copias se ejecutan como root en web01, porque hay que leer archivos como /etc o los directorios de todos los usuarios. En web01, crea una clave SSH para root sin frase de paso, para que el timer pueda usarla sin intervención:
sudo ssh-keygen -t ed25519 -f /root/.ssh/borg_ed25519 -N '' -C 'borg-web01'
sudo cat /root/.ssh/borg_ed25519.pub
Copia la línea que empieza por ssh-ed25519.
En el servidor de copias, añade esa clave a authorized_keys del usuario borg, pero restringida: con la opción command, esa clave solo puede ejecutar borg serve y solo sobre su propio repositorio. Aunque alguien robe la clave de web01, no obtendrá una shell ni podrá tocar los repositorios de otros servidores:
sudo nano /srv/borg/.ssh/authorized_keys
command="borg serve --restrict-to-path /srv/borg/web01",restrict ssh-ed25519 AAAAC3Nza... borg-web01
Ajusta los permisos del archivo:
sudo chown borg:borg /srv/borg/.ssh/authorized_keys
sudo chmod 600 /srv/borg/.ssh/authorized_keys
Si el servidor de copias tiene UFW activo, asegúrate de que el puerto SSH está permitido (sudo ufw allow OpenSSH).
Paso 4: Inicializar el repositorio cifrado
El resto de pasos se ejecutan en web01 como root. Abre una shell de root:
sudo -i
Genera una frase de paso aleatoria y guárdala en un archivo que solo root pueda leer:
install -m 600 /dev/null /root/.borg-passphrase
openssl rand -base64 32 > /root/.borg-passphrase
Define las variables que Borg lee del entorno: la URL del repositorio, cómo obtener la frase de paso y qué clave SSH usar:
export BORG_REPO='ssh://borg@backup_server_ip/srv/borg/web01'
export BORG_PASSCOMMAND='cat /root/.borg-passphrase'
export BORG_RSH='ssh -i /root/.ssh/borg_ed25519'
Inicializa el repositorio con cifrado repokey-blake2 (autenticado con BLAKE2b, más rápido que SHA-256 en la mayoría de CPU sin aceleración específica):
borg init --encryption=repokey-blake2
La primera vez SSH te pedirá aceptar la huella del servidor de copias. Borg muestra después un aviso como este:
IMPORTANT: you will need both KEY AND PASSPHRASE to access this repo!
...
Comprueba que el repositorio responde:
borg info
Repository ID: 5c1e0f...
Location: ssh://borg@backup_server_ip/srv/borg/web01
Encrypted: Yes (repokey BLAKE2b)
...
Paso 5: Exportar la clave y guardar la frase de paso
Aunque la clave está dentro del repositorio, si este se corrompe perderías el acceso a todos los datos. Exporta una copia de la clave:
borg key export "$BORG_REPO" /root/borg-web01.key
Guarda fuera de ambos servidores el archivo /root/borg-web01.key y el contenido de /root/.borg-passphrase, por ejemplo en tu gestor de contraseñas. Si web01 se pierde por completo, son lo único que necesitarás, junto con el repositorio, para restaurar.
Advertenciasin la frase de paso no hay forma de descifrar las copias. No continúes hasta haberla guardado en un lugar seguro.
Paso 6: Hacer la primera copia
Crea un archivo con los directorios importantes. {hostname} y {now} son marcadores que Borg sustituye por el nombre del host y la fecha; el :: indica que el repositorio se toma de BORG_REPO:
borg create --stats --compression zstd,6 --exclude-caches \
--exclude '/home/*/.cache' \
--exclude '/var/tmp/*' \
::'{hostname}-{now:%Y-%m-%dT%H:%M}' \
/etc /home /root /var/www
Qué hacen las opciones:
--compression zstd,6comprime con zstd, un buen equilibrio entre velocidad y tamaño.--exclude-cachesomite los directorios marcados con un archivoCACHEDIR.TAG.--excludeomite rutas con patrones de tipo shell.
Al terminar, --stats muestra un resumen:
Archive name: web01-2026-09-25T10:31
Number of files: 18342
Original size Compressed size Deduplicated size
This archive: 1.92 GB 842.13 MB 801.77 MB
All archives: 1.92 GB 842.13 MB 801.77 MB
Ejecuta el mismo comando otra vez y observa la columna Deduplicated size de This archive: al no haber cambios, será de unos pocos kilobytes. Esa es la cantidad de espacio nuevo que ocupa cada copia.
Lista los archivos del repositorio:
borg list
web01-2026-09-25T10:31 Thu, 2026-09-25 10:31:02 [3b0c...]
web01-2026-09-25T10:36 Thu, 2026-09-25 10:36:44 [9e41...]
Consejono copies los archivos de datos de MySQL o PostgreSQL en caliente. Genera antes un volcado con
mysqldumpopg_dumpen un directorio incluido en la copia.
Paso 7: Automatizar las copias con un script y systemd
Crea un script que haga la copia, aplique la retención y libere espacio. Sal de la shell de root con exit y crea el archivo:
sudo nano /usr/local/sbin/borg-backup.sh
#!/usr/bin/env bash
set -uo pipefail
export BORG_REPO='ssh://borg@backup_server_ip/srv/borg/web01'
export BORG_PASSCOMMAND='cat /root/.borg-passphrase'
export BORG_RSH='ssh -i /root/.ssh/borg_ed25519'
borg create --stats --compression zstd,6 --exclude-caches \
--exclude '/home/*/.cache' \
--exclude '/var/tmp/*' \
::'{hostname}-{now:%Y-%m-%dT%H:%M}' \
/etc /home /root /var/www
create_exit=$?
borg prune --list --glob-archives '{hostname}-*' \
--keep-daily 7 --keep-weekly 4 --keep-monthly 6
prune_exit=$?
borg compact
compact_exit=$?
# Borg devuelve 0 (correcto), 1 (aviso) o 2 (error). Se devuelve el peor.
exit_code=$(( create_exit > prune_exit ? create_exit : prune_exit ))
exit_code=$(( compact_exit > exit_code ? compact_exit : exit_code ))
exit "$exit_code"
El script no usa set -e a propósito: si borg create termina con un aviso (código 1, por ejemplo porque un archivo cambió durante la lectura), la retención y la compactación deben ejecutarse igualmente.
borg pruneconserva las últimas 7 copias diarias, 4 semanales y 6 mensuales, y marca el resto para borrar.--glob-archiveslimita la retención a los archivos de este host.borg compactlibera en disco el espacio de los archivos borrados. En Borg 1.2 es un paso obligatorio trasprune.
Hazlo ejecutable y solo accesible por root:
sudo chmod 700 /usr/local/sbin/borg-backup.sh
Crea la unidad de servicio:
sudo nano /etc/systemd/system/borg-backup.service
[Unit]
Description=Copia de seguridad con BorgBackup
Wants=network-online.target
After=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/borg-backup.sh
Nice=10
IOSchedulingClass=idle
Y el timer, que la ejecuta cada noche a las 02:00 con un retraso aleatorio de hasta 15 minutos:
sudo nano /etc/systemd/system/borg-backup.timer
[Unit]
Description=Copia diaria con BorgBackup
[Timer]
OnCalendar=*-*-* 02:00:00
RandomizedDelaySec=15m
Persistent=true
[Install]
WantedBy=timers.target
Persistent=true hace que, si el servidor estaba apagado a esa hora, la copia se ejecute al arrancar. Activa el timer y lanza una ejecución manual para probar el servicio:
sudo systemctl daemon-reload
sudo systemctl enable --now borg-backup.timer
sudo systemctl start borg-backup.service
Revisa el resultado en el registro:
sudo journalctl -u borg-backup.service -n 20 --no-pager
La salida debe incluir las estadísticas de borg create y la lista de borg prune sin errores. Comprueba la próxima ejecución programada:
systemctl list-timers borg-backup.timer
NEXT LEFT LAST PASSED UNIT ACTIVATES
Fri 2026-09-26 02:07:13 CEST 15h left - - borg-backup.timer borg-backup.service
Paso 8: Restaurar archivos
Para trabajar con el repositorio de forma interactiva, abre una shell de root y exporta de nuevo las tres variables del paso 4.
Lista el contenido de un archivo concreto, filtrando por ruta:
borg list ::web01-2026-09-25T10:36 etc/nginx
Borg guarda las rutas sin la / inicial y borg extract restaura en el directorio actual. Por eso lo más seguro es extraer en un directorio temporal y copiar después lo que necesites:
mkdir -p /tmp/restore && cd /tmp/restore
borg extract --list ::web01-2026-09-25T10:36 etc/nginx
etc/nginx
etc/nginx/nginx.conf
etc/nginx/sites-available/default
...
Compara con la versión actual y, si es la correcta, cópiala a su sitio:
diff -r /tmp/restore/etc/nginx /etc/nginx
cp -a /tmp/restore/etc/nginx/. /etc/nginx/
Para restaurar un servidor completo, instala Borg en el servidor nuevo, importa la clave si el repositorio estuviera dañado (borg key import), configura el acceso SSH y extrae los directorios necesarios de la misma forma.
Paso 9: Verificar el repositorio
borg check comprueba la consistencia del repositorio y de los archivos. Ejecútalo periódicamente, por ejemplo una vez al mes:
borg check
Si no muestra errores y termina con código 0, el repositorio está bien. La opción --verify-data además descifra y verifica todos los datos, lo que es más fiable pero mucho más lento en repositorios grandes.
Una comprobación no sustituye a una restauración de prueba: extrae de vez en cuando un directorio completo y verifica que la aplicación funciona con él.
Solución de problemas
Remote: borg: command not found. Borg no está instalado en el servidor de copias. Instala el paquete borgbackup allí.
Failed to create/acquire the lock. Otra ejecución sigue en curso o una anterior se interrumpió. Si estás seguro de que no hay ningún borg en marcha en ningún servidor, libera el bloqueo con borg break-lock.
passphrase supplied in BORG_PASSCOMMAND is incorrect. El archivo /root/.borg-passphrase no contiene la frase con la que se creó el repositorio o tiene un salto de línea de más. Recupérala desde tu gestor de contraseñas.
Repository path not allowed. La ruta de BORG_REPO no está dentro de la indicada en --restrict-to-path en authorized_keys.
Conclusión
Tienes copias diarias cifradas y deduplicadas de web01 en un servidor remoto, con una clave SSH que solo puede ejecutar borg serve, retención automática y un procedimiento de restauración probado. Como siguientes pasos, añade borg check mensual a otro timer, envía una alerta cuando borg-backup.service falle (por ejemplo con OnFailure= en la unidad) y respalda más servidores creando un repositorio y una clave restringida para cada uno.
