#!/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. # ===================================================================== # Safety Switches set -euo pipefail # Logs Error Messages trap 'echo "[$(date)] ERROR: Script failed at Line ${LINENO} with Exit Code $?."' ERR # --------------------------------------------------------------------- # Configuration # --------------------------------------------------------------------- DB_HOST="localhost" 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 KEEP_DAILY=7 KEEP_WEEKLY=28 KEEP_MONTHLY=365 # 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 # --------------------------------------------------------------------- TIMESTAMP=$(date +"%Y-%m-%d_%H-%M-%S") DAY_OF_WEEK=$(date +"%u") # 1=Monday ... 7=Sunday DAY_OF_MONTH=$(date +"%d") mkdir -p "${BACKUP_DIR_DAILY}" "${BACKUP_DIR_WEEKLY}" "${BACKUP_DIR_MONTHLY}" # --------------------------------------------------------------------- # Create Daily Backup in compressed Custom Format # --------------------------------------------------------------------- DAILY_FILE="${BACKUP_DIR_DAILY}/webgis_${TIMESTAMP}.dump" echo "[$(date)] Starting daily Backup -> ${DAILY_FILE}" pg_dump \ --host="${DB_HOST}" \ --port="${DB_PORT}" \ --username="${DB_USER}" \ --format=custom \ --compress=9 \ --file="${DAILY_FILE}" \ "${DB_NAME}" # 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)." # --------------------------------------------------------------------- # Promote to Weekly Backup on Sundays # --------------------------------------------------------------------- if [[ "${DAY_OF_WEEK}" == "7" ]]; then cp "${DAILY_FILE}" "${BACKUP_DIR_WEEKLY}/webgis_${TIMESTAMP}.dump" echo "[$(date)] Promoted to weekly Backup." fi # --------------------------------------------------------------------- # Promote to Monthly Backup on the First of the Month # --------------------------------------------------------------------- if [[ "${DAY_OF_MONTH}" == "01" ]]; then cp "${DAILY_FILE}" "${BACKUP_DIR_MONTHLY}/webgis_${TIMESTAMP}.dump" echo "[$(date)] Promoted to monthly Backup." fi # --------------------------------------------------------------------- # 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."