86 lines
3.4 KiB
Bash
86 lines
3.4 KiB
Bash
#!/usr/bin/env bash
|
|
# /home/spuser/PassKeeper/scripts/backup_db.sh
|
|
#
|
|
# Automated MySQL backup for PassKeeper.
|
|
# - Dumps the passkeeper database with mysqldump
|
|
# - Compresses with gzip
|
|
# - Retains the last 30 daily backups
|
|
# - Logs all actions with timestamps
|
|
# - Exits non-zero on any failure so cron can email on error
|
|
#
|
|
# Usage:
|
|
# chmod +x scripts/backup_db.sh
|
|
# # Test manually:
|
|
# bash scripts/backup_db.sh
|
|
# # Schedule via cron (see scripts/backup.cron)
|
|
|
|
set -euo pipefail
|
|
|
|
# ── Configuration ─────────────────────────────────────────────────────────────
|
|
ENV_FILE="$(dirname "$(realpath "$0")")/../.env"
|
|
|
|
# Load .env variables
|
|
if [[ -f "$ENV_FILE" ]]; then
|
|
set -o allexport
|
|
# shellcheck disable=SC1090
|
|
source "$ENV_FILE"
|
|
set +o allexport
|
|
else
|
|
echo "ERROR: .env file not found at $ENV_FILE" >&2
|
|
exit 1
|
|
fi
|
|
|
|
BACKUP_DIR="${BACKUP_DIR:-/home/spuser/backups/passkeeper}"
|
|
RETENTION_DAYS="${BACKUP_RETENTION_DAYS:-30}"
|
|
TIMESTAMP="$(date +%Y%m%d_%H%M%S)"
|
|
BACKUP_FILE="${BACKUP_DIR}/passkeeper_${TIMESTAMP}.sql.gz"
|
|
LOG_FILE="${BACKUP_DIR}/backup.log"
|
|
|
|
# MySQL credentials from .env
|
|
DB_HOST="${MYSQL_HOST:-127.0.0.1}"
|
|
DB_PORT="${MYSQL_PORT:-3306}"
|
|
DB_USER="${MYSQL_USER:-passkeeper}"
|
|
DB_PASS="${MYSQL_PASSWORD}"
|
|
DB_NAME="${MYSQL_DB:-passkeeper}"
|
|
|
|
# ── Helpers ───────────────────────────────────────────────────────────────────
|
|
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"; }
|
|
|
|
# ── Pre-flight ────────────────────────────────────────────────────────────────
|
|
mkdir -p "$BACKUP_DIR"
|
|
chmod 700 "$BACKUP_DIR"
|
|
|
|
log "INFO Starting backup → $BACKUP_FILE"
|
|
|
|
# ── Dump ─────────────────────────────────────────────────────────────────────
|
|
# --single-transaction: consistent snapshot without locking (InnoDB)
|
|
# --routines --events: include stored procedures/events if any
|
|
# --no-tablespaces: avoid PROCESS privilege requirement on MySQL 8+
|
|
mysqldump \
|
|
--host="$DB_HOST" \
|
|
--port="$DB_PORT" \
|
|
--user="$DB_USER" \
|
|
--password="$DB_PASS" \
|
|
--single-transaction \
|
|
--routines \
|
|
--events \
|
|
--no-tablespaces \
|
|
"$DB_NAME" \
|
|
| gzip -9 > "$BACKUP_FILE"
|
|
|
|
BACKUP_SIZE="$(du -sh "$BACKUP_FILE" | cut -f1)"
|
|
log "INFO Backup complete — size: $BACKUP_SIZE"
|
|
|
|
# ── Verify the file is non-empty ──────────────────────────────────────────────
|
|
if [[ ! -s "$BACKUP_FILE" ]]; then
|
|
log "ERROR Backup file is empty — aborting retention cleanup"
|
|
exit 1
|
|
fi
|
|
|
|
# ── Retention: delete backups older than RETENTION_DAYS ──────────────────────
|
|
DELETED=$(find "$BACKUP_DIR" -maxdepth 1 -name 'passkeeper_*.sql.gz' \
|
|
-mtime +"$RETENTION_DAYS" -print -delete | wc -l)
|
|
log "INFO Retention cleanup: removed $DELETED file(s) older than ${RETENTION_DAYS} days"
|
|
|
|
log "INFO Backup finished successfully"
|