Consent Docs

Back up and restore

Back up the database and the secrets of a self-hosted deployment, restore them, and know what a restore loses or repeats.

How-to2 min readFor project administrators and deployment operators

Back up the database at least once a day, and always before an upgrade. scripts/backup.sh takes the backup, and Test a restore shows that it can be restored. The restore commands use the supplied compose file.

What to back up#

What How often Why
The PostgreSQL database All the time with point-in-time recovery if you can, or at least daily It holds everything: settings, records, evidence, anchors and the audit log
ENCRYPTION_KEY, SUBJECT_HASH_PEPPER, EVIDENCE_CHAIN_KEYS, RECEIPT_SIGNING_PRIVATE_KEY, RECEIPT_SIGNING_KEY Once, and after each rotation Without them a restored database cannot be read, searched or verified
Your .env and compose override files When they change To rebuild the deployment
The public key set from /sdk/v1/keys Once, and after a signing key change To verify old receipts offline

Redis needs no backup. It holds sessions and rate-limit counters.

Take a backup#

  1. Set the database variables the API uses: DB_HOST, DB_PORT, DB_USERNAME, DB_PASSWORD and DB_DATABASE.

  2. With the supplied compose file, set DB_CONTAINER=piedap-consent-postgres as well. The script then runs pg_dump inside that container.

  3. Run the script from the repository.

    Shell
    BACKUP_DIR=/srv/backups/consent scripts/backup.sh
  4. Save the public key set, the first time and after a signing key change.

    Shell
    curl -s https://consent.example.in/sdk/v1/keys > keys-$(date +%F).json
  5. Encrypt the files and store them away from the host.

The script writes three files named after the database and the UTC time, such as piedap-consent-piedap_consent-20261009T013000Z.dump.

File What it holds
.dump The database, in the custom format of pg_dump
.dump.sha256 The SHA-256 of the dump
.counts The rows of each table, counted in the same snapshot as the dump

The password reaches PostgreSQL as PGPASSWORD and is never printed. To remove old backups, set BACKUP_KEEP_DAYS to the days to keep.

Restore#

  1. Stop the API and the console, so nothing is written during the restore.

    Shell
    docker compose stop consent-api consent-web
  2. Drop the database and create it again. An empty database holds nothing that a newer version added. dropdb refuses while another client is connected.

    Shell
    docker exec piedap-consent-postgres \
      dropdb -U postgres --if-exists piedap_consent
    docker exec piedap-consent-postgres \
      createdb -U postgres piedap_consent
  3. Restore the dump.

    Shell
    docker exec -i piedap-consent-postgres \
      pg_restore -U postgres -d piedap_consent \
      < piedap-consent-piedap_consent-20260918T013000Z.dump
  4. Start an API image that matches the restored schema, or a newer one. A newer image applies its migrations on start.

    Shell
    docker compose start consent-api consent-web
  5. Check that the API answers 200.

    Shell
    curl -s http://127.0.0.1:8080/health
  6. Sign in, open Audit. In Evidence anchors, choose Verify on the most recent days.

  7. Choose Verify the log.

The restore worked when /health shows "database": "up", and the anchors and the log verify.

After a restore#

Tell your customers what was lost and what repeats.

  • Consent recorded after the backup is gone. Customers who stored their evidence.anchored deliveries hold anchors for days that are now missing or different. Tell them which period is affected.
  • Webhooks may be sent twice. Events that waited in the outbox at backup time go out again. Each event body has an id. Receivers should ignore an id they have already handled.

↑↓ to move, Enter to open