Skip to main content

max / makenotwork

2.5 KB · 66 lines History Blame Raw
1 #!/bin/bash
2 # Makenotwork Database Backup Script
3 # Runs daily via cron, keeps 30 days of backups.
4 #
5 # Usage: backup-db.sh [db_name]
6 # db_name defaults to "makenotwork". Pass "multithreaded" (or any other
7 # DB) to back up that one instead. The script runs as the corresponding
8 # OS user (peer auth), so call from that user's crontab.
9 #
10 # Setup (per DB user):
11 # 1. Deploy script to /opt/mnw/backup-db.sh (chmod 755)
12 # 2. Ensure /var/lib/mnw/backups exists and is writable by the DB user
13 # 3. Add cron job as that user:
14 # sudo crontab -u <db_user> -e
15 # # Daily at 03:00 UTC:
16 # 0 3 * * * /opt/mnw/backup-db.sh <db_name> >> /var/lib/mnw/backups/<db_name>/backup.log 2>&1
17
18 set -euo pipefail
19
20 DB_NAME="${1:-makenotwork}"
21 DB_USER="$DB_NAME" # peer auth: OS user matches DB user
22 BACKUP_DIR="/var/lib/mnw/backups/${DB_NAME}"
23 RETENTION_DAYS=30
24
25 TIMESTAMP=$(date +%Y%m%d-%H%M%S)
26 BACKUP_FILE="${BACKUP_DIR}/${DB_NAME}-${TIMESTAMP}.sql.gz"
27
28 echo "[$(date -Iseconds)] Starting backup of ${DB_NAME}..."
29
30 mkdir -p "$BACKUP_DIR"
31 # Move into the backup dir so later `find ... -delete` doesn't fail when invoked
32 # from a CWD the DB user can't traverse (e.g. /root under `sudo -u`).
33 cd "$BACKUP_DIR"
34
35 pg_dump -U "$DB_USER" "$DB_NAME" | gzip > "$BACKUP_FILE"
36
37 FILESIZE=$(stat -c%s "$BACKUP_FILE" 2>/dev/null || stat -f%z "$BACKUP_FILE" 2>/dev/null)
38 if [ "$FILESIZE" -lt 100 ]; then
39 echo "[$(date -Iseconds)] ERROR: Backup file suspiciously small (${FILESIZE} bytes)"
40 exit 1
41 fi
42
43 echo "[$(date -Iseconds)] Backup complete: $BACKUP_FILE ($(du -h "$BACKUP_FILE" | cut -f1))"
44
45 # Stable per-DB latest filename for downstream pullers (sando's backup-puller
46 # user rsyncs `latest-<db>.sql.gz`). Hard link rather than symlink because rrsync
47 # blocks `-L`; atomic via temp-then-rename so the link is never briefly missing.
48 LATEST="${BACKUP_DIR}/latest.sql.gz"
49 ln -f "$BACKUP_FILE" "${LATEST}.new"
50 mv -Tf "${LATEST}.new" "$LATEST"
51
52 DELETED=$(find "$BACKUP_DIR" -name "${DB_NAME}-*.sql.gz" -mtime +${RETENTION_DAYS} -delete -print | wc -l)
53 if [ "$DELETED" -gt 0 ]; then
54 echo "[$(date -Iseconds)] Pruned $DELETED ${DB_NAME} backup(s) older than ${RETENTION_DAYS} days"
55 fi
56
57 TOTAL=$(find "$BACKUP_DIR" -name "${DB_NAME}-*.sql.gz" | wc -l)
58 echo "[$(date -Iseconds)] Total ${DB_NAME} backups on disk: $TOTAL"
59
60 # Sync to offsite host (best-effort — failure here does not fail the backup).
61 SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
62 OFFSITE_SCRIPT="${SCRIPT_DIR}/sync-backup-offsite.sh"
63 if [ -x "$OFFSITE_SCRIPT" ]; then
64 "$OFFSITE_SCRIPT" "$DB_NAME" "$BACKUP_FILE" || true
65 fi
66