Skip to content

Backups and restore

Scheduled backups, restore drill into an ephemeral container, end-to-end verification.

scripts/backup.sh pipes pg_dump --clean --if-exists --no-owner through gzip and writes a timestamped .sql.gz to /var/backups/pulse/.

Schedule with cron or systemd:

15 3 * * * /opt/pulse/scripts/backup.sh

Also snapshot Traefik’s acme.json (see Self-hosting → TLS) and Redis if you care about queue depth at restore time (usually you don’t — workers refill on demand).

scripts/restore.sh <backup.sql.gz> boots a fresh ephemeral Postgres container on port 15432, replays the dump, and prints a count report.

Terminal window
scripts/restore.sh /var/backups/pulse/pulse-2026-05-19.sql.gz
# [restore] starting ephemeral postgres on :15432
# [restore] applying dump...
# [restore] table rows
# [restore] monitors 342
# [restore] users 18
# [restore] organizations 3
# [restore] incidents 1102
# [restore] alert_rules 27
# [restore] OK

Override the port with RESTORE_PORT=15440.

scripts/backup-test.sh ties it together: take a backup of the running dev DB → restore into the ephemeral instance → run sanity SQL → cleanup. Run it monthly. If it ever fails, you’ve found a backup format change before you needed it.