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.

Cómo realizar copias de seguridad con Borg en tu NAS o servidor UnRAID
Regístrate en HDS+
Es gratuito. Ten acceso a todo el contenido.
🔓
Dificultad del tutorial: Media

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.

Borg Documentation — Borg - Deduplicating Archiver 1.2.7 documentation

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

✏️
Los datos que se ven en este apartado son exclusivamente para el ejemplo de este tutorial.

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
👉
La ruta elegida debe estar completamente vacía o no podremos continuar.

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:

✏️
Si no tienes un bot de telegram, crearlo es gratuito y se tardan 10 segundos. Habla con @BotFather y con @cid_bot
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

👉
Recuerda que tienes que cambiar la parte izquierda de las rutas, el /bkp-from/XXX y el PUID y PGID. Revisa con cuidado esta parte.

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.

Pasted Graphic 17.png

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:

GitHub - dgongut/borgmatic-script
Contribute to dgongut/borgmatic-script development by creating an account on GitHub.

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.

👉
Por convención deberá tener la extensión .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):

Pasted Graphic 13.png

Una vez tengamos el fichero completo, lo guardamos y hemos terminado esta parte.


Programación de las copias de seguridad

✏️
En mi caso el contenedor se llama 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

⚠️
IMPORTANTE: Para que el bot de telegram nos pueda escribir hay que interactuar antes con él. Iniciad una conversación con él y presionad en el botón Iniciar. Esto mandará al bot un /start.

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
Pasted Graphic 23.png
✏️
El disco que he usado ya contenía datos, por lo que aparecen ocupados 3.4TB.

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.

Pasted Graphic 24.png
✏️
El tamaño modificado ha sido de 1.28KB, correspondiente a la modificación del fichero 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 en este tercer punto os falla con algún error del montaje es debido a que el contenedor no se está ejecutando con altos privilegios

Si todo ha ido bien ya tendremos las copias montadas como si fueran carpetas en la carpeta llamada HISTORICO.

Pasted Graphic 25.png

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

⚠️
IMPORTANTE: Este paso es de vital importancia. De no realizarlo podría quedar el repositorio bloqueado y no se podrían realizar copias sobre él.
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.

Pasted Graphic 29.png

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
👉
En este ejemplo el contenedor que quiero parar se llama 'micontenedor'
⚠️
IMPORTANTE: Hacer una copia de seguridad de una base de datos sin pararla puede dar lugar a una copia de seguridad errónea.

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.

✏️
Un dump de una base de datos contiene toda la información de configuración de usuarios, tablas y datos, de manera que se puede volver a aplicar para restaurar la información.
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"
⚠️
IMPORTANTE: El ejemplo está realizado con el usuario root de la BBDD ya que por defecto es el único que puede exportar. Lo ideal sería darle ese permiso al usuario no-root que usemos para leer/insertar. Evitando así usar el usuario root y tener ahí su contraseña en texto plano.
👉
En este ejemplo;
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
👉
La ruta que tiene UnRAID por defecto para montar discos duros externos es /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
👉
La ruta que tiene UnRAID para montar rutas remotas es /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
👉
En nuestro caso el repositorio es /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:

✏️
¿Por qué no se ve nada en los repositorios?
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.

Invítame a un café



Más artículos

Dozzle: visualizador de logs en tiempo real para tus Dockers

Dozzle: visualizador de logs en tiempo real para tus Dockers

Monitoriza todos tus Docker a golpe de clic. Visualiza todos los registros en una misma plataforma.

Por Joan
Instala la alternativa SelfHosted a WeTransfer en tu NAS

Instala la alternativa SelfHosted a WeTransfer en tu NAS

Envíe archivos por enlace o correo electrónico, de forma privada o pública, utilizando Pingvin Share.

Por Joan
Cómo instalar FreshRSS en tu NAS o servidor unRAID

Cómo instalar FreshRSS en tu NAS o servidor unRAID

Instala tu servidor Self-Hosted de agregador de noticias. Configuración y primeros pasos explicados.

Por Joan