Bloque C de la fase SaaS (ficheros; el despliegue se hace con el runbook): - docker-compose.prod.yml: superficie mínima (solo el frontend en 127.0.0.1:8089 para el nginx nativo), límites de memoria, sin seeder. - deploy/nginx-recordalexia.conf: server block con cabeceras de seguridad, X-Forwarded-For para el rate-limiter y preparado para certbot. - deploy/backup.sh: pg_dump diario comprimido, retención 14, copia externa vía rclone y detección de backups vacíos. - .env.prod.example (y .env.prod en .gitignore). - docs/operacion-saas.md: runbook con primer despliegue, checklist, restore ENSAYADO paso a paso, actualización y problemas conocidos.
53 lines
2.1 KiB
Bash
Executable File
53 lines
2.1 KiB
Bash
Executable File
#!/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
|