SafeGrd / PostgreSQL backup

PostgreSQL backups that are restored on a schedule

SafeGrd backs up PostgreSQL 13 and later from any host that can reach the database. It takes the schema with pg_dump and the rows over binary COPY, both from one snapshot. Each backup is compressed and encrypted on that host, written to S3-compatible storage under Object Lock, and then restored on a schedule to check that every table and row came back.

Run your first Fire Drill Read the install guide

curl -fsSL https://safegrd.dev/install.sh | sh
safegrd backup --database-url "$DATABASE_URL" --retention-days 14
safegrd verify --snapshot <newest> --sandbox-target "$SANDBOX_URL"

What each backup holds

What a Fire Drill checks

A Fire Drill restores the newest backup and compares it with the manifest written when the backup was taken: the number of tables, the rows in each, the columns, and the installed extensions. A sandbox drill loads it into a throwaway database, which also proves the schema, constraints and triggers load. The result is signed and added to your record, and a failed drill alerts your team. Your plan sets how often drills run (pricing).

Where it runs

The daemon runs on a server beside the database, in a Docker container, on Kubernetes through the Helm chart, or in a scheduled GitHub Actions job. It needs a network path to PostgreSQL and a pg_dump at least as new as the server.

How to restore

Create an empty database and point the restore at it. The command works on any host that has the CLI and the key, not only the host that took the backup.

createdb recovered
safegrd restore --snapshot SNAPSHOT_ID --target "postgres://user:pass@host:5432/recovered"

The target has to be empty: the restore refuses a database that already holds tables, so it never writes over data. To put one schema back into a database that has others, add --schema NAME.

The target runs the same PostgreSQL major version as the backup's server, or a newer one. The whole restore is one transaction, and every table's row count is checked against the manifest before it commits (Restore and Fire Drills).

Questions

Does it need a superuser?

A read-only role is enough. On PostgreSQL 14 and later, grant it pg_read_all_data, which covers tables created later as well. Row-level security still applies to that role, so give it BYPASSRLS or back up as the tables' owner to capture every row. The backup lists each table RLS applied to (Databases).

Does it replace pgBackRest or WAL archiving?

SafeGrd takes logical backups, so it restores to the moment of a backup, not to any minute in between. If you need point-in-time recovery, keep pgBackRest or WAL-G for that and run SafeGrd beside it for a tested, encrypted copy in a separate account (SafeGrd vs pgBackRest).

Can I restore into a newer PostgreSQL version?

A logical backup loads into an empty database on the same major version or a newer one, which is how many teams upgrade. safegrd restore refuses a target that already holds tables, so a restore never writes over data.

Who holds the decryption key?

You choose when the key is made. With a SafeGrd-managed key, SafeGrd keeps your key sealed and releases it only to your enrolled hosts, so you can restore even after losing a host. With a customer-managed key, only you can decrypt these backups. The console shows which one you chose.

Related