#!/usr/bin/env bash # backup-db.sh — Daily PostgreSQL backup to MinIO # # Run on the production server via cron: # 0 3 * * * /opt/performancewest/scripts/backup-db.sh >> /var/log/pw-backup.log 2>&1 # # Backs up: # - api-postgres (performancewest DB) — orders, fees, sessions # - umami-postgres (umami DB) — analytics # # Retention: 30 days (older backups deleted automatically) set -euo pipefail TIMESTAMP=$(date +%Y%m%d_%H%M%S) BUCKET="${MINIO_BUCKET:-performancewest}" MINIO_ALIAS="pwminio" # ── Setup mc alias ──────────────────────────────────────────────────────────── mc alias set "${MINIO_ALIAS}" \ "http://minio:9000" \ "${MINIO_ACCESS_KEY:-performancewest}" \ "${MINIO_SECRET_KEY:-changeme}" \ --quiet 2>/dev/null || true # ── Helper ──────────────────────────────────────────────────────────────────── backup_db() { local container="$1" local db_name="$2" local pg_user="$3" local label="$4" local filename="${label}_${TIMESTAMP}.sql.gz" local minio_path="${MINIO_ALIAS}/${BUCKET}/backups/${filename}" echo "[$(date -u +%H:%M:%S)] Backing up ${label} → ${minio_path}" docker exec "${container}" \ pg_dump -U "${pg_user}" "${db_name}" \ | gzip \ | mc pipe "${minio_path}" echo "[$(date -u +%H:%M:%S)] ${label} backup complete: ${filename}" } # ── Run backups ─────────────────────────────────────────────────────────────── backup_db "api-postgres" "performancewest" "pw" "performancewest" backup_db "umami-postgres" "umami" "umami" "umami" # ── Prune backups older than 30 days ───────────────────────────────────────── echo "[$(date -u +%H:%M:%S)] Pruning backups older than 30 days..." mc rm --recursive --force --older-than 30d \ "${MINIO_ALIAS}/${BUCKET}/backups/" 2>/dev/null || true echo "[$(date -u +%H:%M:%S)] Backup run complete."