Skip to content

Backups and restore

Plugboard takes encrypted, scheduled backups of itself. Getting them off the machine, and having restored one, is yours.

SECRETS_MASTER_KEY must be backed up somewhere that is not the server it protects.

Connector credentials and the backups themselves are encrypted with it. A database restored without that key cannot decrypt its own secrets. Every integration would need to be reconfigured from scratch, assuming you still have the original credentials, and if you do not, some of them are gone.

Put a copy in a password manager. Not in a file next to the backup. Not in the same cloud account. Somewhere a total loss of the server does not also lose.

Admin, Backups (/admin/backups), gated by the module.backups module and the backup.manage permission.

From there you can:

  • Schedule backups to run automatically, with a retention policy.
  • Run one on demand.
  • Verify a backup’s integrity, which reads it back and checks it decrypts and parses.
  • Export a portable per-tenant copy, for moving or handing over an institution’s data.

If a scheduled backup fails, an alert is raised and, if email is configured, the backup.failed message is sent. That message cannot be switched off.

Backups are encrypted, so they can be handed to your existing backup tooling and off-site storage without a second encryption layer and without worrying about who can read them at rest.

Full detail on the screen itself: backups in the app.

IncludedNot included
Every database table for the tenantThe SECRETS_MASTER_KEY itself
Encrypted connector credentialsUploaded files in object storage, if you use external S3
Configuration, roles, workflow, templatesThe application binaries
Audit log, within retention

If you use external object storage for logos, photos and exports, back that bucket separately. If you are on the portable bundle, uploads live inside the install folder and are covered by copying it.

Pick one and actually implement it. A backup that has only ever existed on the machine it protects is not a backup.

The whole folder, for the portable bundle. Everything is inside the install directory, so a nightly file-level copy of C:\Plugboard or /opt/plugboard to another host covers it. Stop the service first, or use a filesystem snapshot, so the database files are consistent.

pg_dump, for a source or Docker install:

Terminal window
docker compose -f docker-compose.prod.yml exec postgres \
pg_dump -U plugboard -Fc plugboard > backups/plugboard-$(date +%F).dump

Then ship backups/ somewhere else with whatever you already use: rsync, Veeam, restic, a cloud sync agent.

Your existing platform backup. If the machine is a VM in a hypervisor you already back up, that is a legitimate answer, provided you have tested restoring one and starting it.

Terminal window
# Stop the application first so nothing writes during the restore.
docker compose -f docker-compose.prod.yml stop api web worker
docker compose -f docker-compose.prod.yml exec -T postgres \
pg_restore -U plugboard -d plugboard --clean --if-exists < backups/plugboard-2026-08-01.dump
docker compose -f docker-compose.prod.yml start api web worker

Restore into a database whose schema matches the version of the application you are about to run. Restoring an older schema under a newer image will fail at startup, which is better than starting and behaving strangely.

Set SECRETS_MASTER_KEY in .env to the value that was in use when the backup was taken, before starting the application. If it does not match, the application starts, the data is all there, and every connector fails to authenticate with a decryption error. That symptom is confusing enough to be worth stating in advance.

Stop the service, replace the folder, start the service. The .env inside it carries the matching key, which is exactly why the folder needs to be treated as sensitive.

CI runs a restore drill against PostgreSQL 16 on every push, so the product’s own backup format is exercised continuously. That proves the format. It does not prove your regime.

Once, before go-live:

  1. Take a backup.
  2. Restore it onto a different machine, or into a second database on the same one.
  3. Point a spare copy of the application at it, with the same SECRETS_MASTER_KEY.
  4. Sign in. Open a submission. Open Admin, Connectors and confirm a connector still tests successfully, which is what proves the secrets decrypted.
  5. Write down how long the whole thing took. That number is your real recovery time, and it is usually larger than people guess.

Then put a reminder in the calendar to do it again once a year, or after any change to how backups are taken.

What you can promise depends on what you have configured, not on the software.

Determined by
Recovery point (how much you can lose)Backup frequency. Nightly means up to a day
Recovery time (how long to be back)How fast you can get the backup to a machine and start it

For managed deployments, the objectives we commit to are in your agreement and backups are taken and tested for you. See support, restores and exits.

Backup retention is set on the Backups screen. Audit log retention is separate and set under audit and retention, because the two answer to different policies: one is operational, the other is often a legal minimum.

The alert tells you which run failed. The usual causes, in order of how often they turn out to be the answer:

  1. Disk full. Check free space on the volume holding backups/.
  2. Retention not pruning, so the disk filled. Check the retention policy is actually set to something.
  3. Permissions, after somebody changed the account the service runs as.
  4. The database was unreachable at that moment, usually because it was restarting.

Run one on demand from the Backups screen once you have fixed it, rather than waiting for the schedule to prove the fix.