improve backup script preflight checks and file size validation

This commit is contained in:
2026-04-17 15:42:02 +02:00
parent 4554ea3ff0
commit 19b038d4f5

View File

@@ -1,13 +1,19 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# ===================================================================== # =====================================================================
# WebGIS Database Backup Script # WebGIS Database Backup Script
# Location: /opt/webgis-lohne/scripts/backup.sh (on server) # Location: /opt/webgis-lohne/scripts/backup.sh (on Server)
# Purpose: Creates compressed pg_dump backups with daily/weekly/monthly # Purpose: Creates compressed pg_dump Backups with daily/weekly/monthly
# rotation. Intended to be run via cron. # Rotation. Intended to be run via Cron.
# ===================================================================== # =====================================================================
# Safety Switches
set -euo pipefail set -euo pipefail
# Logs Error Messages
trap 'echo "[$(date)] ERROR: Script failed at Line ${LINENO} with Exit Code $?."' ERR
# --------------------------------------------------------------------- # ---------------------------------------------------------------------
# Configuration # Configuration
# --------------------------------------------------------------------- # ---------------------------------------------------------------------
@@ -16,21 +22,49 @@ DB_PORT="5432"
DB_NAME="webgis-db" DB_NAME="webgis-db"
DB_USER="webgis-db-admin" DB_USER="webgis-db-admin"
BACKUP_ROOT="/var/backups/webgis" BACKUP_ROOT="/var/backups/webgis"
BACKUP_DIR_DAILY="${BACKUP_ROOT}/daily" BACKUP_DIR_DAILY="${BACKUP_ROOT}/daily"
BACKUP_DIR_WEEKLY="${BACKUP_ROOT}/weekly" BACKUP_DIR_WEEKLY="${BACKUP_ROOT}/weekly"
BACKUP_DIR_MONTHLY="${BACKUP_ROOT}/monthly" BACKUP_DIR_MONTHLY="${BACKUP_ROOT}/monthly"
# Retention Periods (in days) # Retention Periods in Days
KEEP_DAILY=7 KEEP_DAILY=7
KEEP_WEEKLY=28 KEEP_WEEKLY=28
KEEP_MONTHLY=365 KEEP_MONTHLY=365
# Password is read from a protected file (see setup instructions). # Minimum acceptable Backup File Size in Bytes
# pg_dump honors the PGPASSFILE environment variable. # 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" 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 # 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" DAILY_FILE="${BACKUP_DIR_DAILY}/webgis_${TIMESTAMP}.dump"
echo "[$(date)] Starting daily backup -> ${DAILY_FILE}" echo "[$(date)] Starting daily Backup -> ${DAILY_FILE}"
pg_dump \ pg_dump \
--host="${DB_HOST}" \ --host="${DB_HOST}" \
@@ -57,7 +91,14 @@ pg_dump \
--file="${DAILY_FILE}" \ --file="${DAILY_FILE}" \
"${DB_NAME}" "${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 if [[ "${DAY_OF_WEEK}" == "7" ]]; then
cp "${DAILY_FILE}" "${BACKUP_DIR_WEEKLY}/webgis_${TIMESTAMP}.dump" cp "${DAILY_FILE}" "${BACKUP_DIR_WEEKLY}/webgis_${TIMESTAMP}.dump"
echo "[$(date)] Promoted to weekly backup." echo "[$(date)] Promoted to weekly Backup."
fi fi
@@ -74,16 +115,15 @@ fi
# --------------------------------------------------------------------- # ---------------------------------------------------------------------
if [[ "${DAY_OF_MONTH}" == "01" ]]; then if [[ "${DAY_OF_MONTH}" == "01" ]]; then
cp "${DAILY_FILE}" "${BACKUP_DIR_MONTHLY}/webgis_${TIMESTAMP}.dump" cp "${DAILY_FILE}" "${BACKUP_DIR_MONTHLY}/webgis_${TIMESTAMP}.dump"
echo "[$(date)] Promoted to monthly backup." echo "[$(date)] Promoted to monthly Backup."
fi 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_DAILY}" -name "*.dump" -mtime +${KEEP_DAILY} -delete
find "${BACKUP_DIR_WEEKLY}" -name "*.dump" -mtime +${KEEP_WEEKLY} -delete find "${BACKUP_DIR_WEEKLY}" -name "*.dump" -mtime +${KEEP_WEEKLY} -delete
find "${BACKUP_DIR_MONTHLY}" -name "*.dump" -mtime +${KEEP_MONTHLY} -delete find "${BACKUP_DIR_MONTHLY}" -name "*.dump" -mtime +${KEEP_MONTHLY} -delete
echo "[$(date)] Backup Rotation complete."
echo "[$(date)] Backup rotation complete."