From 5f6fc075eddefc97d4173c3d35f0d5d78335e251 Mon Sep 17 00:00:00 2001 From: "bert.hausmans" Date: Wed, 6 May 2026 08:13:46 +0200 Subject: [PATCH] feat: glitchtip postgres backup script MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Daily pg_dump → gzip → retention pipe for the GlitchTip database. Configurable via env vars (defaults: ./backups/glitchtip, 30-day retention, glitchtip-postgres container). Streams directly through gzip so no plaintext dump touches disk; output 0600. Cron example in the script header. RFC-WS-7-OBSERVABILITY §5 acceptance criterion 11. Co-Authored-By: Claude Opus 4.7 (1M context) --- scripts/glitchtip-backup.sh | 55 +++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100755 scripts/glitchtip-backup.sh diff --git a/scripts/glitchtip-backup.sh b/scripts/glitchtip-backup.sh new file mode 100755 index 00000000..6363fb6e --- /dev/null +++ b/scripts/glitchtip-backup.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash +# +# glitchtip-backup.sh — daily postgres dump for the GlitchTip database. +# +# Usage: +# bash scripts/glitchtip-backup.sh +# +# Cron example (production host): +# # /etc/cron.d/glitchtip-backup +# 0 3 * * * crewli /opt/crewli/scripts/glitchtip-backup.sh >> /var/log/glitchtip-backup.log 2>&1 +# +# Configurable via env vars (defaults shown): +# GLITCHTIP_BACKUP_DIR=./backups/glitchtip +# GLITCHTIP_BACKUP_RETENTION_DAYS=30 +# GLITCHTIP_DB_CONTAINER=glitchtip-postgres +# GLITCHTIP_DB_USER=postgres +# GLITCHTIP_DB_NAME=glitchtip +# +# Restore (full): +# gunzip < .gz \ +# | docker exec -i glitchtip-postgres pg_restore -U postgres -d glitchtip --clean --if-exists +# +# Per RFC-WS-7-OBSERVABILITY §5 (daily postgres-backup) and acceptance +# criterion 11. See dev-docs/GLITCHTIP.md for the full restore drill. + +set -euo pipefail + +BACKUP_DIR="${GLITCHTIP_BACKUP_DIR:-./backups/glitchtip}" +RETENTION_DAYS="${GLITCHTIP_BACKUP_RETENTION_DAYS:-30}" +DB_CONTAINER="${GLITCHTIP_DB_CONTAINER:-glitchtip-postgres}" +DB_USER="${GLITCHTIP_DB_USER:-postgres}" +DB_NAME="${GLITCHTIP_DB_NAME:-glitchtip}" + +mkdir -p "$BACKUP_DIR" + +timestamp="$(date +%Y%m%d-%H%M%S)" +output="$BACKUP_DIR/glitchtip-${timestamp}.dump.gz" + +echo "[$(date -Iseconds)] Dumping ${DB_NAME} from ${DB_CONTAINER} to ${output}" + +# Stream pg_dump (custom format) directly through gzip — no intermediate file. +# `set -o pipefail` already in effect so a pg_dump failure aborts before retention. +docker exec -i "$DB_CONTAINER" \ + pg_dump -U "$DB_USER" -d "$DB_NAME" --format=custom --no-owner --no-privileges \ + | gzip -c > "$output" + +chmod 0600 "$output" + +size="$(wc -c < "$output" | tr -d ' ')" +echo "[$(date -Iseconds)] Wrote ${output} (${size} bytes)" + +echo "[$(date -Iseconds)] Pruning dumps older than ${RETENTION_DAYS} days" +find "$BACKUP_DIR" -type f -name 'glitchtip-*.dump.gz' -mtime "+${RETENTION_DAYS}" -print -delete + +echo "[$(date -Iseconds)] Done."