Cómo realizar copias de seguridad con Borg en tu NAS o servidor UnRAID
Compresión, deduplicación, encriptación y multiplataforma. Borg, la solución definitiva.
Regístrate en HDS+
Tutoriales y soporte sobre sistemas NAS, Redes, Docker y SelfHosting.
Sin SPAM. Es gratuito. Ten acceso a todo el contenido.
En el tutorial de hoy, quiero compartir el programa de copias de seguridad que utilizo en mi día a día. Este software destaca por incorporar funciones de compresión, deduplicación y encriptación para nuestras copias versionadas. Su nombre es Borg. Además, he desarrollado un script que se encargará de notificarnos a través de Telegram fácilmente configurable.
Presentaré un uso básico en el que podremos realizar nuestras copias versionadas y recuperar ficheros de una copia específica.
Para cualquier duda de funcionamiento, mensajes de error o hacer uso de sus otras múltiples opciones, os enlazo la documentación oficial.
Requisitos previos
- Identificar las rutas de aquellas carpetas de las que queramos tener una copia.
- Identificar la ruta de destino de las copias. Puede ser un HDD externo, un disco duro interno, una ruta SMB/NFS, lo que queramos que ya se encuentre montado en el servidor (con una ruta disponible)
- Tener una carpeta donde almacenar los logs.
- Tener un bot de telegram donde recibiremos las notificaciones (token y chatId).
Preparativos
En mi caso, las carpetas que me interesa copiar son las siguientes:
/volume1/docker
/volume1/test
El destino de la copia la realizaré en una carpeta de un HDD externo cuya ruta es la siguiente:
/volumeUSB1/usbshare/COPIA_BORG
Mis ficheros de logs los almacenaré en una carpeta compartida llamada logs.
/volume1/logs
He creado mi bot de telegram y estos son sus datos:


@BotFather para la creación del bot y @cid_bot para la obtención del chatID de nuestro usuario
TOKEN="6319625328:AAHxLIgeshx0C68spwr6heNsAsZHeG2qKRo"
ID="4405089"
Instalación de Borg

En nuestra carpeta donde almacenemos los datos de los contenedores docker deberemos crear las siguiente estructura de carpetas:
borg
├── borg_keys
├── cache
├── config
├── ssh_keys
└── restore
En mi caso se ubican en /volume1/docker/
services:
borgmatic:
container_name: borg
network_mode: bridge
environment:
- TZ=Europe/Madrid
- PUID=1026
- PGID=100
volumes:
- /volume1/docker/borg/cache:/root/.cache/borg:rw
- /volume1/docker/borg/config:/etc/borgmatic.d:rw
- /volume1/docker/borg/borg_keys:/root/.config/borg:rw
- /volume1/docker/borg/ssh_keys:/root/.ssh:rw
- /volume1/docker/borg/restore:/restore:rw
- /volume1/docker:/bkp-from/docker/:ro
- /volume1/test:/bkp-from/test/:ro
- /volumeUSB1/usbshare/COPIA_BORG:/bkp-HDD:rw
- /volume1/logs:/remote_logs:rw
cap_add:
- SYS_ADMIN
image: ghcr.io/borgmatic-collective/borgmatic
docker-compose de ejemplo
En Synology
Creamos las carpetas descritas en la ruta de /docker/borg
, así como un fichero docker-compose.yaml con el docker-compose anterior modificado.
Crearemos un nuevo proyecto en Container Manager.
Seleccionamos la carpeta de borg
y nos autodetectará el fichero.




Una vez instalado, para el correcto funcionamiento en Synology es necesario ejecutar este contenedor con altos privilegios. Para ello una vez creado, lo detenemos y en configuración marcamos la siguiente opción.


La instalación en unRAID es lo más sencillo del mundo, ya que lo único que tendremos que hacer será bajarnos la imagen de borgmatic a través de su plantilla oficial y configurar todas las rutas tal cual están descritas en el docker-compose.


Inicialización del repositorio
Para poder hacer copias de seguridad con borg, el destino (denominado por borg como repositorio) ha de ser inicializado. Vamos a ello.
Accederemos al contenedor mediante terminal.
En Synology: es necesario "crear" una terminal y seleccionarla.



En UnRAID: Clic sobre el icono de borg en la pestaña docker y clic en 'Terminal'

Ejecutamos la siguiente instrucción para inicializar el repositorio:
borg init --encryption=repokey /bkp-HDD
Nos pedirá una contraseña con la cual cifraremos las copias de seguridad (nos la pedirá 2 veces). Para este tutorial a modo de ejemplo la mía será 1234
.
Al finalizar nos preguntará si queremos mostrar la contraseña, escribimos la letra y
para que nos la muestre.
Al terminar nos debería aparecer algo así (entre comillas la contraseña elegida).

Ya habríamos terminado con la inicialización del repositorio y estaría listo para empezar a realizar copias.
Script para realizar las copias de seguridad
Nos basaremos en mi script (enlace directo para copiar y pegar).
El repositorio completo es el siguiente:
Lo copiaremos y lo dejaremos en la ruta que tengamos mapeada en /etc/borgmatic.d
en mi caso sería en /volume1/docker/borg/config
. Le pondré el nombre startborg.sh
.
Dentro de él, en las primeras líneas nos encontramos todo lo que podemos modificar, aunque viene descrito, os resumo brevemente lo que cambiaré:
BORG_REPO: Repositorio de destino (/bkp-HDD en mi caso)
BORG_PASSPHRASE: Contraseña del repositorio (1234 en mi caso)
LOG: Fichero log incluyendo ruta, en nuestro caso /remote_logs/borg.log
SERVER_NAME: Nombre del servidor (este dato no se podrá cambiar una vez realizada la primera copia)
PATHS_TO_COPY: Rutas a copiar separadas por espacios, en mi caso "/bkp-from/docker /bkp-from/test"
DAILY: Guarda al menos una copia de los últimos X días
WEEKLY: Guarda al menos una copia de las últimos X semanas
MONTHLY: Guarda al menos una copia de los últimos X meses
TOKEN: token de Telegram
ID: ChatID del bot/grupo/canal de telegram
DOCUMENT_NAME: Nombre del fichero de texto sin espacios que será enviado por Telegram
DESTINATION_NAME: Nombre del destino (en mi caso pondré HDD)
Las primeras líneas deberían quedar algo parecido a esto (pero con vuestros datos):

Una vez tengamos el fichero completo, lo guardamos y hemos terminado esta parte.
Programación de las copias de seguridad
borg
y el script se llama startborg.sh
La tarea en sí es la siguiente:
#!/bin/bash
docker exec borg bash -c "/etc/borgmatic.d/startborg.sh"
Para crear dicha tarea en Synology haremos lo siguiente:
- Panel de control ➜ Programador de tareas ➜ Crearemos una tarea programada ➜ Script definido por el usuario (usuario root).



En UnRAID:
- Usaremos el plugin UserScripts
- Ajustes ➜ UserScripts ➜ Add New Script
- Le ponemos el nombre que queramos e introducimos el comando
- Establecemos la frecuencia que queramos





Primera copia de seguridad
Esta primera copia no es especial en absoluto, simplemente hagámosla para comprobar el funcionamiento.
En Synology: Se marca la tarea y pulsamos en Ejecutar
En UnRAID: Se pulsa el boton Run in background
Si todo ha ido bien, en Telegram, ya nos debe haber escrito el bot con la siguiente información:
- Mensaje de inicio de la copia
- Si ha finalizado de manera exitosa o no
- El tiempo transcurrido
- El espacio ocupado en el disco de destino
- Entre paréntesis el espacio de los datos que se han añadido/modificado
- Fichero de logs

Ya tenemos nuestra primera copia realizada con éxito.
A modo de ejemplo, voy a modificar un fichero de la carpeta test para quitarle información. Posteriormente realizaré una segunda copia.

test.txt
.Restauración de los datos
Estaremos de acuerdo en que estos sistemas hay que probarlos y que de nada sirve tener una copia si no sabemos cómo restaurar los datos.
Para restaurar los datos hay que seguir unos sencillos pasos; comenzaremos entrando dentro del contenedor mediante terminal (como cuando generamos el repositorio)
Crearemos una carpeta para el montaje del repositorio. A esta carpeta la llamaré HISTORICO
mkdir HISTORICO
Montaremos el repositorio en la carpeta HISTORICO. Nos pedirá la contraseña en este paso.
borg mount bkp-HDD HISTORICO
Si todo ha ido bien ya tendremos las copias montadas como si fueran carpetas en la carpeta llamada HISTORICO.

Extra no necesario: instalaré el programa tree dentro del contenedor para pintar de manera gráfica la estructura de las carpetas y hacer más visual el tutorial. Quizá os venga bien al principio para ubicar bien dónde encontrar vuestros ficheros si no estáis muy familiarizados con la terminal.
Para instalar el programa ejecutamos:
apk add tree
Para usarlo:
tree -L 4 /HISTORICO
La salida:
HISTORICO
├── SATURNO-2023-12-12T23:27:47
│ └── bkp-from
│ ├── docker
│ │ ├── @eaDir
│ │ ├── WebDAV-Victor
│ │ ├── borg
│ │ ├── firefox
│ │ ├── saturno_notificaciones
│ │ ├── speedtest
│ │ └── teledock
│ └── test
│ ├── @eaDir
│ └── test.txt
└── SATURNO-2023-12-12T23:35:27
└── bkp-from
├── docker
│ ├── @eaDir
│ ├── WebDAV-Victor
│ ├── borg
│ ├── firefox
│ ├── saturno_notificaciones
│ ├── speedtest
│ └── teledock
└── test
├── @eaDir
└── test.txt
Opcional pero altamente recomendable: comprobar el contenido de lo que vamos a restaurar.
Parece obvio, pero muchas veces en los momentos de desesperación con prisas restauramos cosas que ya estaban rotas. Ahora voy a comprobar el contenido de ambos ficheros test.txt.

Como vemos, la primera versión de las 23:27 era la correcta.
Extracción de los datos del contenedor
Copiaremos lo que nos interese a la carpeta /restore
. Pueden ser ficheros o incluso carpetas enteras.
cp origen destino
cp -r carpeta_origen/. destino
El /. del final de la carpeta deseada nos asegura copiar todo el contenido de la carpeta incluyendo archivos ocultos.
En mi caso, al no ser una carpeta, no es necesario el parámetro -r
:
cp HISTORICO/SATURNO-2023-12-12T23\:27\:47/bkp-from/test/test.txt restore
Desmontaremos el repositorio de la carpeta HISTORICO
borg umount HISTORICO
Eliminaremos la carpeta HISTORICO
rmdir HISTORICO

Visualizando los datos desde el host
Si todo ha ido bien, nos podemos dirigir a la carpeta (en mi caso) /volume1/docker/borg/restore
en nuestro servidor fuera del contenedor y allí estará el fichero o carpeta que hemos restaurado, listo para ser copiado/movido a donde realmente hacía falta.

Opcional EXTRAS
Parar contenedores
Algunas veces, al realizar la copia de carpetas que se están usando durante el proceso, puede hacer de esta, una copia no válida. Estas carpetas, en mi caso siempre han sido las de algunos contenedores en específico.
Una buena práctica, aunque no siempre es posible por temas de disponibilidad, sería detener aquellos contenedores que cuenten con base de datos durante la copia de seguridad. Por lo que la tarea programada tendría un aspecto como este:
#!/bin/bash
docker stop micontenedor
docker exec borg bash -c "/etc/borgmatic.d/startborg.sh"
docker start micontenedor
Exportar bases de datos para su copia en caliente
En ciertas ocasiones no siempre es posible detener un contenedor porque de él depende un servicio en producción o similar. Es por eso, que para hacer una copia correcta de un contenedor de base de datos sin necesidad de detenerla, hay que realizar lo que se conoce como dump y guardarlo en alguna carpeta a la cual le vayamos a hacer backup.
Se trata de una forma segura de hacer copias de seguridad de bases de datos en caliente.
Cada tipo de base de datos tendrá una forma diferente de realizar y aplicar un dump, es por eso que he elegido la más común: MariaDB.
La tarea programada tendría un aspecto parecido a este:
#!/bin/bash
docker exec mariadb bash -c "export MYSQL_PWD='LaPasswordDelUsuarioRoot' && cd /config && mariadb-dump -u root miDB > miDB.sql"
docker exec borg bash -c "/etc/borgmatic.d/startborg.sh"
El contenedor es una BBDD de MariaDB que se llama 'mariadb'.
La base de datos que quiero exportar se llama 'miDB'.
El fichero dump se llamará 'miDB.sql'.
La ruta dentro del contenedor que tengo mapeada hacia el exterior es
/config
, que es donde se encuentran la base de datos y donde acabará el fichero dump.Montar USB/NFS externo
Por lo general, es muy raro que queramos hacer una copia dentro del mismo servidor (además de no ser recomendable).
El problema viene cuando ese disco duro o esa ruta de red está siempre montada, ya que, de ocurrir un desastre de tipo ransomware, también encriptaría la carpeta que tengamos montada. ¿Cómo lo he solucionado? Montando la unidad de red / USB justo antes de la copia y desmontando tras la copia.
En UnRAID con un HDD tendría este aspecto:
#!/bin/bash
mkdir /mnt/disks/HDD
mount /dev/sda1 /mnt/disks/HDD
docker exec borg bash -c "/etc/borgmatic.d/startborg.sh"
umount /mnt/disks/HDD
rmdir /mnt/disks/HDD
/mnt/disks
por lo que la respetamos creando ahí una carpeta.El
/dev/sda1
se refiere a la partición del disco duro que quiero montar. Para conocer este dato, basta con tener el HDD conectado y montado de manera habitual y ejecutar el comando blkid
en la terminal del servidor.En UnRAID con NFS tendría este aspecto:
#!/bin/bash
mkdir /mnt/remotes/SATURNO
sudo mount -t nfs 192.168.5.179:/volume1/UnRAID /mnt/remotes/SATURNO
docker exec borg bash -c "etc/borgmatic.d/startborg_saturno.sh"
umount /mnt/remotes/SATURNO
rmdir /mnt/remotes/SATURNO
/mnt/remotes
por lo que la respetamos creando ahí una carpeta.La ruta de red
192.168.5.179:/volume1/UnRAID
es una ruta que ese servidor expone para NFS.Error más típico
Vamos a montar el repositorio y error.
Vamos a hacer una copia de seguridad y... error. Siempre el mismo error:
Failed to create/acquire the lock /bkp-HDD/lock.exclusive (timeout).
terminating with error status, rc 2
Este error es el más típico y se suele producir por un corte del script antes de terminar la copia anterior o bien porque no hemos desmontado el repositorio y se nos ha parado el contenedor... o por muchos motivos.
Si estamos seguros de que el repositorio no está montado en la carpeta HISTORICO y que la copia anterior no se está ejecutando, podemos lanzar sin miedo el comando:
borg break-lock /bkp-HDD
/bkp-HDD
Múltiples destinos, un contenedor
Lo ideal en las copias de seguridad es seguir la recomendación 321, lo que implica copiar a más de un destino.
¿Voy a tener que montar otro contenedor igual para cada destino? No, basta con mapear otro destino además del que ya tenemos, por ejemplo en /bkp-remote
y tener otro script startborg.sh
al que podríamos llamar startborg_remote.sh
. De esta manera incluso podríamos diferenciar si queremos copiar a un sitio unas carpetas u otras, diferentes horarios y frecuencia, diferente retención... las limitaciones están en tu imaginación.
Solo echa un vistazo a modo de ejemplo de los destinos que realmente tengo en mi servidor:

Porque si no voy a hacer una copia, se encuentran desmontados 😉
Al principio puede abrumar un poco, pero es extremadamente sencillo, una vez automatizado todo, cuando quieras recuperar algo solo es montar el repositorio copiar lo que te interese y desmontar.
Espero que os haya sido de utilidad este tutorial y podáis proteger vuestros datos como se merecen.