- src/lib/rate-limit.ts (Redis sliding window, fail-open) - before-hook on /sign-in/email: 5 attempts/min per IP+email - worker job audit-archive (daily 03:30, JSONL → MinIO, 90d retention) - worker job panel-backup (daily 04:00, pg_dump -Fc -Z9 → MinIO) - Dockerfile adds postgresql16-client - scripts/restore-drill.sh restores latest dump into panel_drill - docs/disaster-recovery.md + docs/phase4-deferred.md (mTLS + Infisical rationale)
58 lines
2.6 KiB
Bash
Executable File
58 lines
2.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Restore drill: pulls the latest panel-postgres dump from MinIO and restores
|
|
# into a throwaway "panel_drill" database, then runs a few SELECT sanity checks.
|
|
#
|
|
# Run on the maestro host. Requires: docker (with access to coolify-db + minio-global).
|
|
#
|
|
# Usage:
|
|
# ./scripts/restore-drill.sh # latest dump
|
|
# ./scripts/restore-drill.sh 2026-05-13T03-00-00 # specific key prefix
|
|
|
|
set -euo pipefail
|
|
|
|
MINIO_CT=${MINIO_CT:-minio-global}
|
|
PG_CT=${PG_CT:-coolify-db}
|
|
BUCKET=${MINIO_BACKUP_BUCKET:-panel-backups}
|
|
PREFIX=${1:-}
|
|
DRILL_DB=${DRILL_DB:-panel_drill}
|
|
|
|
if ! sudo docker ps --format '{{.Names}}' | grep -q "^${MINIO_CT}$"; then
|
|
echo "minio container '${MINIO_CT}' not running" >&2
|
|
exit 1
|
|
fi
|
|
|
|
ROOT_USER=$(sudo docker exec "$MINIO_CT" sh -c 'echo $MINIO_ROOT_USER')
|
|
ROOT_PASS=$(sudo docker exec "$MINIO_CT" sh -c 'echo $MINIO_ROOT_PASSWORD')
|
|
|
|
echo "==> finding latest dump in $BUCKET/panel-postgres/"
|
|
sudo docker exec "$MINIO_CT" sh -c "mc alias set local http://localhost:9000 '$ROOT_USER' '$ROOT_PASS' >/dev/null" || true
|
|
LATEST=$(sudo docker exec "$MINIO_CT" sh -c "mc ls --recursive local/$BUCKET/panel-postgres/ 2>/dev/null | sort | tail -1 | awk '{print \$NF}'")
|
|
[ -n "$LATEST" ] || { echo "no dumps found" >&2; exit 1; }
|
|
echo "==> latest: $LATEST"
|
|
|
|
TMP=$(mktemp /tmp/panel-drill.XXXXXX.dump)
|
|
trap 'rm -f "$TMP"' EXIT
|
|
|
|
echo "==> downloading…"
|
|
sudo docker exec "$MINIO_CT" sh -c "mc cp local/$BUCKET/panel-postgres/$LATEST /tmp/drill.dump >/dev/null"
|
|
sudo docker cp "$MINIO_CT":/tmp/drill.dump "$TMP"
|
|
sudo docker exec "$MINIO_CT" rm -f /tmp/drill.dump || true
|
|
|
|
echo "==> dropping + recreating $DRILL_DB on $PG_CT"
|
|
sudo docker exec "$PG_CT" psql -U coolify -d postgres -c "DROP DATABASE IF EXISTS $DRILL_DB;" >/dev/null
|
|
sudo docker exec "$PG_CT" psql -U coolify -d postgres -c "CREATE DATABASE $DRILL_DB OWNER coolify;" >/dev/null
|
|
|
|
echo "==> pg_restoring…"
|
|
sudo docker cp "$TMP" "$PG_CT":/tmp/drill.dump
|
|
sudo docker exec "$PG_CT" pg_restore --clean --if-exists -U coolify -d "$DRILL_DB" /tmp/drill.dump
|
|
sudo docker exec "$PG_CT" rm -f /tmp/drill.dump
|
|
|
|
echo "==> sanity checks"
|
|
sudo docker exec "$PG_CT" psql -U coolify -d "$DRILL_DB" -c '\dt'
|
|
sudo docker exec "$PG_CT" psql -U coolify -d "$DRILL_DB" -c 'SELECT count(*) FROM "User";'
|
|
sudo docker exec "$PG_CT" psql -U coolify -d "$DRILL_DB" -c 'SELECT count(*) FROM "Project";'
|
|
sudo docker exec "$PG_CT" psql -U coolify -d "$DRILL_DB" -c 'SELECT count(*) FROM "AuditLog";'
|
|
|
|
echo "==> drill OK. Drop the drill DB when done:"
|
|
echo " sudo docker exec $PG_CT psql -U coolify -d postgres -c 'DROP DATABASE $DRILL_DB;'"
|