#!/bin/sh # One database backup: pg_dump -> gzip [-> openssl AES-256] -> timestamped file in # $BACKUP_DIR, then prune to the newest $BACKUP_KEEP files. # # Encryption: if BACKUP_ENC_PASSPHRASE is set, the dump is encrypted at rest with # AES-256 (openssl, PBKDF2) and written as *.sql.gz.enc. STRONGLY recommended once # the database holds customer IP — otherwise the dump (and every offsite copy) is # plaintext. Keep the passphrase OUT of the backups directory (and off the host if # possible); losing it means the backups are unrecoverable. # # Runs inside a container that has pg_dump + openssl (see scripts/backup.Dockerfile). set -eu BACKUP_DIR="${BACKUP_DIR:-/backups}" KEEP="${BACKUP_KEEP:-14}" PGHOST="${PGHOST:-db}" PGPORT="${PGPORT:-5432}" DB="${POSTGRES_DB:?POSTGRES_DB is required}" DB_USER="${POSTGRES_USER:?POSTGRES_USER is required}" export PGPASSWORD="${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}" ENC="${BACKUP_ENC_PASSPHRASE:-}" mkdir -p "$BACKUP_DIR" ts="$(date -u +%Y%m%d-%H%M%SZ)" if [ -n "$ENC" ]; then out="$BACKUP_DIR/wpsuite-$ts.sql.gz.enc" else out="$BACKUP_DIR/wpsuite-$ts.sql.gz" echo "[db-backup] WARNING: BACKUP_ENC_PASSPHRASE not set — this dump is UNENCRYPTED. Set it to protect data at rest." >&2 fi tmp="$out.partial" echo "[db-backup] $(date -u) dumping ${DB}@${PGHOST} -> ${out}" if [ -n "$ENC" ]; then if pg_dump -h "$PGHOST" -p "$PGPORT" -U "$DB_USER" -d "$DB" --clean --if-exists \ | gzip -c \ | openssl enc -aes-256-cbc -pbkdf2 -salt -pass env:BACKUP_ENC_PASSPHRASE > "$tmp"; then mv "$tmp" "$out" else echo "[db-backup] FAILED — pg_dump/encrypt error" >&2; rm -f "$tmp"; exit 1 fi else if pg_dump -h "$PGHOST" -p "$PGPORT" -U "$DB_USER" -d "$DB" --clean --if-exists | gzip -c > "$tmp"; then mv "$tmp" "$out" else echo "[db-backup] FAILED — pg_dump error" >&2; rm -f "$tmp"; exit 1 fi fi echo "[db-backup] wrote $(du -h "$out" | cut -f1) ${out}" # Retention: keep the newest $KEEP dumps (plaintext or encrypted), delete the rest. count="$(ls -1t "$BACKUP_DIR"/wpsuite-*.sql.gz* 2>/dev/null | grep -v '\.partial$' | wc -l | tr -d ' ')" if [ "$count" -gt "$KEEP" ]; then ls -1t "$BACKUP_DIR"/wpsuite-*.sql.gz* 2>/dev/null | grep -v '\.partial$' | tail -n +"$((KEEP + 1))" | while IFS= read -r f; do echo "[db-backup] pruning $f" rm -f "$f" done fi