Ir al contenido

Automatizar backups incrementales de PostgreSQL y Docker con restic hacia MinIO

Rogelio Guerra Riverón
Autor
Rogelio Guerra Riverón
Construyendo mi propia infraestructura web desde cero. Aquí documento cada paso: servidores, redes, contenedores y lo que vaya surgiendo.

Llevo tiempo queriendo mejorar mi estrategia de backups en el servidor doméstico. Tener todo en Docker está bien, pero necesitaba algo más robusto que simplemente copiar archivos. Restic + MinIO resultó ser la combinación perfecta: backups incrementales, deduplicación y un S3 local sin depender de servicios en la nube.

Por qué esta combinación
#

Restic es incremental por defecto, solo almacena lo que cambió. MinIO corre en el mismo servidor y expone una API S3 compatible, lo que evita dependencias externas. PostgreSQL se respalda en volúmenes Docker que también necesitan protección. Todo automatizado con cron.

Instalación base
#

Primero, restic:

sudo apt-get install restic

MinIO ya está corriendo en Docker. Si no lo tienes:

docker run -d \
  --name minio \
  -p 9000:9000 \
  -p 9001:9001 \
  -e MINIO_ROOT_USER=minioadmin \
  -e MINIO_ROOT_PASSWORD=tupassword \
  -v /data/minio:/data \
  minio/minio server /data --console-address ":9001"

Luego creo un usuario y bucket específicos para backups en la consola de MinIO (puerto 9001).

Configurar restic con MinIO
#

Inicializo el repositorio:

export AWS_ACCESS_KEY_ID=backup-user
export AWS_SECRET_ACCESS_KEY=tu-clave-secreta
export RESTIC_REPOSITORY=s3:http://localhost:9000/backups
export RESTIC_PASSWORD=tu-password-restic

restic init

Guardo estas variables en un archivo seguro que solo el usuario root puede leer:

# /root/.restic-env
export AWS_ACCESS_KEY_ID=backup-user
export AWS_SECRET_ACCESS_KEY=tu-clave-secreta
export RESTIC_REPOSITORY=s3:http://localhost:9000/backups
export RESTIC_PASSWORD=tu-password-restic
chmod 600 /root/.restic-env

Backup de PostgreSQL
#

PostgreSQL en Docker requiere un dump antes de respaldar. Creo un script:

#!/bin/bash
# /root/backup-postgres.sh

set -e
source /root/.restic-env

BACKUP_DIR="/tmp/postgres-backup"
mkdir -p $BACKUP_DIR

# Dump de la base de datos
docker exec postgres-container pg_dump -U postgres -d tu_database > \
  $BACKUP_DIR/database-$(date +%s).sql

# Backup con restic
restic backup $BACKUP_DIR --tag postgres

# Limpio
rm -rf $BACKUP_DIR

Backup de volúmenes Docker
#

Para los volúmenes de datos:

#!/bin/bash
# /root/backup-volumes.sh

set -e
source /root/.restic-env

# Respalda volúmenes específicos montándolos
docker run --rm -v mi_volumen:/data \
  -v /root:/root:ro \
  -w /data \
  alpine/restic:latest backup /data --tag docker-volumes

Mejor aún, respaldo directamente la ruta donde Docker almacena los volúmenes:

restic backup /var/lib/docker/volumes/mi_volumen/_data --tag docker-volumes

Automatización con cron
#

Creo un script maestro que ejecuta ambos backups:

#!/bin/bash
# /root/backup-all.sh

source /root/.restic-env

/root/backup-postgres.sh 2>&1 | logger -t restic-pg
/root/backup-volumes.sh 2>&1 | logger -t restic-vol

# Purgar snapshots antiguos (mantener 7 días)
restic forget --keep-daily 7 --keep-monthly 3 --prune
chmod +x /root/backup-all.sh

En crontab:

# Cron - ejecuta a las 2 AM diariamente
0 2 * * * /root/backup-all.sh

Verificación y mantenimiento
#

Para ver el estado de los backups:

restic snapshots
restic stats

Para probar una restauración (sin tocar nada):

restic restore latest --target /tmp/test-restore

Lo que aprendí
#

La deduplicación de restic es potente; después del primer backup, los incrementales son mínimos. MinIO ocupa poco espacio si configurás bien su limpieza de versiones antiguas. El dump de PostgreSQL debe hacerse antes del backup, no hay forma de respaldar la base activa sin riesgo de corrupción.

Este setup me da tranquilidad. Si algo falla en el servidor, tengo backups automáticos, versionados y recuperables en cuestión de minutos.