Walwarden Docs
Backup

Scheduled backups

How to configure the backup schedule and what the worker does on each run.

Setting the schedule

On the database detail page in the walwarden dashboard, the Schedule section shows the current cron expression. A blank schedule means no automatic backups run.

Enter a cron expression in five-field UTC format:

minute  hour  day-of-month  month  day-of-week

Examples:

IntentCron
Every hour, on the hour0 * * * *
Every 6 hours0 */6 * * *
Daily at 02:00 UTC0 2 * * *
Every 12 hours (02:00 and 14:00 UTC)0 2,14 * * *

Click Save schedule. The change takes effect immediately; the next backup runs at the next matching tick.

What the worker does on each run

  1. Claims a backup_job row and transitions it from queued to claimed.
  2. Opens a connection to the source database using the stored DSN.
  3. Starts a pg_dump --format=custom --compress=9 subprocess, streaming stdout to S3 via multipart upload.
  4. Computes a SHA256 checksum of the dump bytes in flight.
  5. Writes the dump object to S3 at the path org/<org-id>/db/<db-id>/backup/<YYYY>/<MM>/<DD>/<job-id>.dump.
  6. Writes a manifest JSON to S3 at the same path with extension .manifest.json. The manifest includes the checksum, size in bytes, Postgres server version, and the job ID.
  7. Signs the manifest with walwarden's Ed25519 private key.
  8. Re-fetches the manifest from S3 and verifies size, checksum, and canonical body equality.
  9. Transitions the job to finalizing, then to completed.
  10. Writes a backup.completed audit event.

If any step fails, the job transitions to a failed state and a backup.failed audit event is written. The dashboard shows the failure and the error classification.

Audit chain entry

Every backup produces the following sequence of audit events:

  • backup.queued — scheduler created the job
  • backup.claimed — worker claimed the job
  • backup.runningpg_dump subprocess started
  • backup.finalizing — dump uploaded; manifest written; verification in progress
  • backup.completed — manifest verified; job sealed

You can view the full audit chain on the backup detail page in the dashboard, or export it as part of an evidence bundle.

RPO and loss window

The dashboard hero shows "Last backup: N minutes ago" based on the finalized_at timestamp of the most recent completed backup job. The "You would lose at most N minutes of data" calculation is the elapsed time since that timestamp.

If the scheduled backup fails, the RPO display reflects the last successful backup, not the failed attempt. A failed backup does not advance the RPO bound.