Automatizar backups en un homelab: estrategias eficientes con Docker

La pérdida de datos en un entorno doméstico no es solo un inconveniente: puede significar horas de configuración reconfigurada desde cero. Afortunadamente, Docker facilita la automatización de backups de manera reproducible y aislada. Este artículo explora soluciones prácticas basadas en contenedores para respaldar bases de datos, archivos y configuraciones de servicios, con ejemplos concretos que funcionan en un homelab.


1. Backup de volúmenes Docker: el ABC del método

Los volúmenes de Docker son persistentes por defecto, pero no automáticos. Utilizando docker cp con un cron anfitrión o scripts personalizados, puedes crear backups de volúmenes específicos sin afectar a otros contenedores.

Ejemplo con SQLite:

# Backup de un volumen llamado "db_data"
docker run --rm -v db_data:/data -v $(pwd)/backups:/backup \
  alpine tar zcvf /backups/db_$(date +%Y%m%d).tar.gz -C /data .

Este comando monta el volumen como fuente (/data), lo empaqueta con tar y lo guarda en ./backups del anfitrión. La fecha en el nombre evita sobrescrituras.

Automatización con cron (Linux):

0 3 * * * docker run --rm -v db_data:/data -v /home/user/backups:/backup alpine tar zcvf /backups/db_$(date +%Y%m%d).tar.gz -C /data .

Para Windows, usa el Task Scheduler con un script PowerShell que ejecute el mismo contenedor.


2. Contenedores para backups específicos: casos de uso

Algunos servicios requieren backups especializados. Docker permite encapsular estas acciones en contenedores dedicados.

Backup de MariaDB/MySQL: Usa mariadb-backup en un contenedor temporal:

docker run --rm --network host -v mariadb_conf:/etc/mysql \
  -v /backups/mysql:/backup mariadb:latest \
  sh -c "mariabackup --backup --user=root --password=tu_pass \
  --target-dir=/backup/mysql_$(date +%Y%m%d)"

Este backup es consistente (con almacenamiento transaccional) y evita problemas de corrupción.

Backup de Home Assistant: Home Assistant Community Store (HACS) tiene backups automáticos, pero un backup externo que incluya configuraciones y bases de datos es clave:

# docker-compose.yml (fragmento)
services:
  backup_ha:
    image: alpine
    volumes:
      - ha_config:/config
      - /backups/ha:/backup
    command: sh -c "tar zcvf /backup/ha_$(date +%Y%m%d).tar.gz -C /config ."
    restart: unless-stopped

Ejecuta este servicio semanalmente con un cron externo.


3. Soluciones todo-en-uno: duplicati y restic

Para backups geográficos o cifrados, herramientas como Duplicati o Restic son ideales. Ambas funcionan perfectamente en Docker.

Duplicati (GUI + CLI):

# docker-compose.yml
services:
  duplicati:
    image: duplicati/duplicati:latest
    ports:
      - 8200:8200
    volumes:
      - duplicati_data:/data
      - /mnt/backups:/backups
      - /home/user:/source
    environment:
      - PUID=1000
      - PGID=1000
    restart: unless-stopped

Configura una tarea de backup en la interfaz web (puerto 8200) para fuentes locales, remotas (Backblaze, Wasabi) o un NAS.

Restic (cliente CLI):

docker run --rm -it \
  -e RESTIC_PASSWORD=tu_clave_cifrado \
  -e AWS_ACCESS_KEY_ID=tu_key \
  -e AWS_SECRET_ACCESS_KEY=tu_secret \
  -v /home/user:/backup \
  restic/restic \
  -r s3:https://s3.wasabisys.com/tu-bucket \
  backup /backup

Para restauraciones:

docker run --rm -it \
  restic/restic -r s3:https://s3.wasabisys.com/tu-bucket \
  restore latest --path /backups/xml-restaurados --target /restaurados

4. Backup de Docker Compose: meta-backup

Los archivos docker-compose.yml definen tus servicios. Un backup que incluya toda la configuración (containers, networks, volúmenes) es esencial.

#!/bin/bash
compose_file="/home/user/docker-compose.yml"
backup_dir="/backups/docker_$(date +%Y%m%d)"

# Exportar estado actual
docker-compose -f $compose_file down || true  # Para evitar conflictos
docker-compose -f $compose_file up -d

# Copiar archivo compose y redes/volúmenes
cp $compose_file $backup_dir/
docker inspect $(docker ps -aq) > $backup_dir/containers_info.json
tar zcvf $backup_dir/volumes.tar.gz -C /var/lib/docker/volumes/ .

Este script conserva el estado actual, incluyendo IDs de contenedores y configuraciones de red.


5. Buenas prácticas y verificación

  • Rotación: Usa logrotate o scripts para eliminar backups antiguos (ej: mantener solo los últimos 30 días).
  • Verificación: Restaurar al menos un backup cada trimestre. Ejemplo con Restic:
    docker run --rm restic/restic -r /backups/test \
      check --read-data-subset=1%
    
  • Seguridad: Nunca dejando credenciales en logs. Usa variables de entorno o Docker secrets.
  • Almacenamiento externo: Combina locales (HDD) con remotos (Backblaze, AWS S3) para redundancia.

6. Ejemplo completo: flujo de backup en un homelab

  1. Servicio de backup diario (volúmenes de Nextcloud, MariaDB, Home Assistant):
    # docker-compose-backup.yml
    services:
      backup_diario:
        image: alpine
        volumes:
          - nextcloud_data:/data/nextcloud
          - mariadb_data:/var/lib/mysql
          - ha_config:/backup/ha
          - /backups/local:/backup
        command: sh -c "tar zcvf /backup/diario_$(date +%Y%m%d).tar.gz /data/nextcloud /var/lib/mysql /backup/ha"
        restart: unless-stopped
    
  2. Backup semanal a Backblaze (usando Duplicati):
    • Configura la tarea en Duplicati para comprimir y cifrar en S3 compatible (Backblaze).
  3. Notificaciones: Integra con Gotify o ntfy para alertas de éxito/error:
    status=$?
    curl -X POST "https://ntfy.sh/TuTopico" \
      -H "Title: Backup Failed" \
      -d "Salió mal el backup de $contenedor"