#!/usr/bin/env bash # Backup diario de la base de datos de recordaLexia (producción). # # Qué hace: # 1. pg_dump comprimido del Postgres del compose de producción. # 2. Retención local: conserva los últimos BACKUP_KEEP (por defecto 14). # 3. Copia FUERA de la VM con rclone si RCLONE_REMOTE está definido # (ej. "b2:recordalexia-backups" o "gdrive:backups/recordalexia"). # # Instalación (cron del usuario en la VM, 03:30 hora de Madrid): # crontab -e # 30 3 * * * /ruta/al/repo/deploy/backup.sh >> $HOME/recordalexia-backup.log 2>&1 # # RESTAURAR: ver docs/operacion-saas.md (procedimiento ensayado paso a paso). set -euo pipefail # --- Configuración (sobreescribible por variables de entorno) --- REPO_DIR="${REPO_DIR:-$(cd "$(dirname "$0")/.." && pwd)}" BACKUP_DIR="${BACKUP_DIR:-$HOME/backups/recordalexia}" BACKUP_KEEP="${BACKUP_KEEP:-14}" RCLONE_REMOTE="${RCLONE_REMOTE:-}" COMPOSE=(docker compose -f "$REPO_DIR/docker-compose.prod.yml" --env-file "$REPO_DIR/.env.prod") # Credenciales de la BD: las mismas del compose (nunca en este script). source "$REPO_DIR/.env.prod" mkdir -p "$BACKUP_DIR" STAMP="$(date +%Y%m%d-%H%M%S)" FILE="$BACKUP_DIR/recordalexia-$STAMP.sql.gz" echo "[$(date -Is)] Iniciando backup -> $FILE" "${COMPOSE[@]}" exec -T postgres pg_dump -U "$DB_USER" "$DB_NAME" | gzip > "$FILE" # El backup vacío o diminuto es un fallo, no un backup. SIZE=$(stat -c%s "$FILE" 2>/dev/null || stat -f%z "$FILE") if [ "$SIZE" -lt 1024 ]; then echo "[$(date -Is)] ERROR: backup sospechosamente pequeño ($SIZE bytes)" >&2 exit 1 fi echo "[$(date -Is)] Backup OK ($SIZE bytes)" # Retención local: borrar los que sobren, del más antiguo al más nuevo. ls -1t "$BACKUP_DIR"/recordalexia-*.sql.gz | tail -n +$((BACKUP_KEEP + 1)) | xargs -r rm -- echo "[$(date -Is)] Retención aplicada (máx. $BACKUP_KEEP locales)" # Copia fuera de la VM (si hay remoto configurado en rclone). if [ -n "$RCLONE_REMOTE" ]; then rclone copy "$FILE" "$RCLONE_REMOTE/" --no-traverse echo "[$(date -Is)] Copia externa OK -> $RCLONE_REMOTE" else echo "[$(date -Is)] AVISO: sin RCLONE_REMOTE; el backup solo existe en esta VM" fi