Files
proxpanel/infra/deploy/configure-db-backup-cron.sh

134 lines
4.0 KiB
Bash
Executable File

#!/usr/bin/env bash
set -Eeuo pipefail
APP_DIR="${APP_DIR:-/opt/proxpanel}"
SECRET_FILE="${SECRET_FILE:-$APP_DIR/.backup.env}"
CRON_FILE="${CRON_FILE:-/etc/cron.d/proxpanel-db-backup}"
BACKUP_LOG="${BACKUP_LOG:-/var/log/proxpanel-db-backup.log}"
RESTORE_LOG="${RESTORE_LOG:-/var/log/proxpanel-db-restore-test.log}"
usage() {
cat <<'EOF'
Usage:
sudo bash infra/deploy/configure-db-backup-cron.sh [--run-now]
Default schedule (UTC):
- 02:15 daily: encrypted DB backup + optional offsite replication
- 02:45 daily: restore test against latest encrypted backup
Alerting:
- backup/restore failures dispatch webhook/email alerts if configured in /opt/proxpanel/.backup.env
EOF
}
log() {
printf '[%s] %s\n' "$(date -u +'%Y-%m-%d %H:%M:%S UTC')" "$*"
}
die() {
printf '[ERROR] %s\n' "$*" >&2
exit 1
}
random_key() {
openssl rand -hex 64 | tr -d '\n'
}
ensure_secret_setting() {
local key="$1"
local value="$2"
if ! grep -q "^${key}=" "$SECRET_FILE"; then
printf '%s=%s\n' "$key" "$value" >>"$SECRET_FILE"
fi
}
main() {
local run_now="false"
if [[ "${1:-}" == "--run-now" ]]; then
run_now="true"
elif [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
usage
exit 0
elif [[ -n "${1:-}" ]]; then
die "Unknown argument: $1"
fi
[[ "${EUID:-$(id -u)}" -eq 0 ]] || die "Run as root (or with sudo)."
[[ -d "$APP_DIR" ]] || die "Missing app dir: $APP_DIR"
if [[ ! -f "$SECRET_FILE" ]]; then
log "Creating $SECRET_FILE"
umask 077
cat >"$SECRET_FILE" <<EOF
BACKUP_ENCRYPTION_KEY=$(random_key)
OFFSITE_BACKUP_ENABLED=false
OFFSITE_S3_BUCKET=
OFFSITE_S3_REGION=us-east-1
OFFSITE_S3_PREFIX=proxpanel/db
OFFSITE_S3_ENDPOINT_URL=
OFFSITE_S3_ACCESS_KEY_ID=
OFFSITE_S3_SECRET_ACCESS_KEY=
OFFSITE_S3_SESSION_TOKEN=
OFFSITE_S3_SSE=
OFFSITE_REPLICA_RETENTION_DAYS=30
BACKUP_ALERT_WEBHOOK_URL=
BACKUP_ALERT_EMAIL_WEBHOOK_URL=
BACKUP_ALERT_EMAIL_TO=
BACKUP_ALERT_SUBJECT_PREFIX=[ProxPanel_Backup]
BACKUP_ALERT_SEND_SUCCESS=false
EOF
fi
chmod 600 "$SECRET_FILE"
ensure_secret_setting "OFFSITE_BACKUP_ENABLED" "false"
ensure_secret_setting "OFFSITE_S3_BUCKET" ""
ensure_secret_setting "OFFSITE_S3_REGION" "us-east-1"
ensure_secret_setting "OFFSITE_S3_PREFIX" "proxpanel/db"
ensure_secret_setting "OFFSITE_S3_ENDPOINT_URL" ""
ensure_secret_setting "OFFSITE_S3_ACCESS_KEY_ID" ""
ensure_secret_setting "OFFSITE_S3_SECRET_ACCESS_KEY" ""
ensure_secret_setting "OFFSITE_S3_SESSION_TOKEN" ""
ensure_secret_setting "OFFSITE_S3_SSE" ""
ensure_secret_setting "OFFSITE_REPLICA_RETENTION_DAYS" "30"
ensure_secret_setting "BACKUP_ALERT_WEBHOOK_URL" ""
ensure_secret_setting "BACKUP_ALERT_EMAIL_WEBHOOK_URL" ""
ensure_secret_setting "BACKUP_ALERT_EMAIL_TO" ""
ensure_secret_setting "BACKUP_ALERT_SUBJECT_PREFIX" "[ProxPanel_Backup]"
ensure_secret_setting "BACKUP_ALERT_SEND_SUCCESS" "false"
log "Making scripts executable"
chmod +x \
"$APP_DIR/infra/deploy/db-backup-encrypted.sh" \
"$APP_DIR/infra/deploy/db-restore-test.sh" \
"$APP_DIR/infra/deploy/db-backup-replicate-offsite.sh" \
"$APP_DIR/infra/deploy/notify-backup-alert.sh" \
"$APP_DIR/infra/deploy/db-backup-job.sh" \
"$APP_DIR/infra/deploy/db-restore-test-job.sh"
log "Installing cron schedule at $CRON_FILE"
cat >"$CRON_FILE" <<'EOF'
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# Encrypted PostgreSQL backup every day at 02:15 UTC
15 2 * * * root APP_DIR=/opt/proxpanel /opt/proxpanel/infra/deploy/db-backup-job.sh >> /var/log/proxpanel-db-backup.log 2>&1
# Restore test every day at 02:45 UTC
45 2 * * * root APP_DIR=/opt/proxpanel /opt/proxpanel/infra/deploy/db-restore-test-job.sh >> /var/log/proxpanel-db-restore-test.log 2>&1
EOF
chmod 644 "$CRON_FILE"
touch "$BACKUP_LOG" "$RESTORE_LOG"
chmod 640 "$BACKUP_LOG" "$RESTORE_LOG"
if [[ "$run_now" == "true" ]]; then
log "Running immediate backup + restore test"
APP_DIR="$APP_DIR" "$APP_DIR/infra/deploy/db-backup-job.sh"
APP_DIR="$APP_DIR" "$APP_DIR/infra/deploy/db-restore-test-job.sh"
fi
log "DB backup/restore cron configured successfully."
}
main "$@"