diff --git a/scripts/backup.sh b/scripts/backup.sh index b3b01ab..2348781 100644 --- a/scripts/backup.sh +++ b/scripts/backup.sh @@ -1,13 +1,19 @@ #!/usr/bin/env bash # ===================================================================== # WebGIS Database Backup Script -# Location: /opt/webgis-lohne/scripts/backup.sh (on server) -# Purpose: Creates compressed pg_dump backups with daily/weekly/monthly -# rotation. Intended to be run via cron. +# Location: /opt/webgis-lohne/scripts/backup.sh (on Server) +# Purpose: Creates compressed pg_dump Backups with daily/weekly/monthly +# Rotation. Intended to be run via Cron. # ===================================================================== + +# Safety Switches set -euo pipefail +# Logs Error Messages +trap 'echo "[$(date)] ERROR: Script failed at Line ${LINENO} with Exit Code $?."' ERR + + # --------------------------------------------------------------------- # Configuration # --------------------------------------------------------------------- @@ -16,21 +22,49 @@ DB_PORT="5432" DB_NAME="webgis-db" DB_USER="webgis-db-admin" + BACKUP_ROOT="/var/backups/webgis" BACKUP_DIR_DAILY="${BACKUP_ROOT}/daily" BACKUP_DIR_WEEKLY="${BACKUP_ROOT}/weekly" BACKUP_DIR_MONTHLY="${BACKUP_ROOT}/monthly" -# Retention Periods (in days) +# Retention Periods in Days KEEP_DAILY=7 KEEP_WEEKLY=28 KEEP_MONTHLY=365 -# Password is read from a protected file (see setup instructions). -# pg_dump honors the PGPASSFILE environment variable. +# Minimum acceptable Backup File Size in Bytes +# Valid Dumps of even empty Databases are several KBs +MIN_BACKUP_SIZE=10000 + +# Password is read from protected File +# pg_dump honors the PGPASSFILE Environment Variable. export PGPASSFILE="/root/.pgpass_webgis" +# --------------------------------------------------------------------- +# Preflight Checks +# --------------------------------------------------------------------- + +# Check pg_dump Availability +if ! command -v pg_dump &> /dev/null; then + echo "[$(date)] ERROR: pg_dump not found. Install postgresql-client." + exit 1 +fi + +# Check Password File Existence and Permissions +if [[ ! -f "${PGPASSFILE}" ]]; then + echo "[$(date)] ERROR: Password File ${PGPASSFILE} not found." + exit 1 +fi + +PGPASS_PERMS=$(stat -c "%a" "${PGPASSFILE}") +if [[ "${PGPASS_PERMS}" != "600" ]]; then + echo "[$(date)] ERROR: ${PGPASSFILE} has Permissions ${PGPASS_PERMS}, expected 600." + exit 1 +fi + + # --------------------------------------------------------------------- # Preparation # --------------------------------------------------------------------- @@ -42,11 +76,11 @@ mkdir -p "${BACKUP_DIR_DAILY}" "${BACKUP_DIR_WEEKLY}" "${BACKUP_DIR_MONTHLY}" # --------------------------------------------------------------------- -# Create Daily Backup (Custom-Format, compressed) +# Create Daily Backup in compressed Custom Format # --------------------------------------------------------------------- DAILY_FILE="${BACKUP_DIR_DAILY}/webgis_${TIMESTAMP}.dump" -echo "[$(date)] Starting daily backup -> ${DAILY_FILE}" +echo "[$(date)] Starting daily Backup -> ${DAILY_FILE}" pg_dump \ --host="${DB_HOST}" \ @@ -57,7 +91,14 @@ pg_dump \ --file="${DAILY_FILE}" \ "${DB_NAME}" -echo "[$(date)] Daily backup complete." +# Verify Backup File Size +BACKUP_SIZE=$(stat -c "%s" "${DAILY_FILE}") +if [[ "${BACKUP_SIZE}" -lt "${MIN_BACKUP_SIZE}" ]]; then + echo "[$(date)] ERROR: Backup File is only ${BACKUP_SIZE} Bytes (Minimum: ${MIN_BACKUP_SIZE}). Dump probably corrupt." + exit 1 +fi + +echo "[$(date)] Daily Backup complete (${BACKUP_SIZE} Bytes)." # --------------------------------------------------------------------- @@ -65,7 +106,7 @@ echo "[$(date)] Daily backup complete." # --------------------------------------------------------------------- if [[ "${DAY_OF_WEEK}" == "7" ]]; then cp "${DAILY_FILE}" "${BACKUP_DIR_WEEKLY}/webgis_${TIMESTAMP}.dump" - echo "[$(date)] Promoted to weekly backup." + echo "[$(date)] Promoted to weekly Backup." fi @@ -74,16 +115,15 @@ fi # --------------------------------------------------------------------- if [[ "${DAY_OF_MONTH}" == "01" ]]; then cp "${DAILY_FILE}" "${BACKUP_DIR_MONTHLY}/webgis_${TIMESTAMP}.dump" - echo "[$(date)] Promoted to monthly backup." + echo "[$(date)] Promoted to monthly Backup." fi # --------------------------------------------------------------------- -# Rotation: Delete Backups Older than Retention Period +# Rotation: Delete Backups older than Retention Period # --------------------------------------------------------------------- find "${BACKUP_DIR_DAILY}" -name "*.dump" -mtime +${KEEP_DAILY} -delete find "${BACKUP_DIR_WEEKLY}" -name "*.dump" -mtime +${KEEP_WEEKLY} -delete find "${BACKUP_DIR_MONTHLY}" -name "*.dump" -mtime +${KEEP_MONTHLY} -delete - -echo "[$(date)] Backup rotation complete." \ No newline at end of file +echo "[$(date)] Backup Rotation complete." \ No newline at end of file