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 .pbk archives are encrypted. Without the matching key, an encrypted archive cannot be restored at all. A separate SQL dump or portable export can restore database records, but encrypted connector credentials within them still need the original key or reconfiguration. Keep every key ID needed by retained archives if you use a master keyring.

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.

When Alert on failure is enabled, a failed backup raises an alert and, if email is configured, sends the backup.failed message. The template itself cannot be disabled.

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.

Included Not included
Every database table for the tenant The SECRETS_MASTER_KEY itself
Encrypted connector credentials Uploaded files in object storage, if you use external S3
Configuration, roles, workflow, templates The application binaries
Audit log, within retention

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

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

A consistent filesystem backup. For a native install, include the install directory and any custom storage paths outside it. For Docker, include the database and application-backup volumes as well as the stack’s configuration. A stack-folder copy alone does not contain named-volume data. Stop the relevant services first or use a consistent snapshot; copying live PostgreSQL files is not a verified database backup.

Download an encrypted backup. A backup run’s Download action produces an encrypted .pbk archive for your off-site tooling. The separate portable Export action produces unencrypted compressed JSON and needs protection as sensitive school data.

Whichever you pick, the copy has to leave this machine. A backup that has only ever existed on the machine it protects is not a backup.

Restore from Admin, Backups, confirming the school’s tenant name. This replaces that school’s database records inside one transaction and preserves existing audit entries. It does not stop or restart the deployment. Arrange a maintenance window and prevent concurrent staff and background writes while performing a recovery; the screen does not manage that window for you.

In the 0.12.0-rc.3 candidate source (deployment status), backup access requires unrestricted campus access and, once any department exists, departments.manage as well as the operation’s backup permission. New logical archives use v3 and record complete school scope. Restoring them preserves paused desks and their ticket history; failure rolls back the whole transaction. The archive’s table set, row counts and relationship links must match the current platform schema.

Older unmarked v1/v2 archives are refused by in-app restore, even for ICT-only schools. They remain downloadable and readable with the matching keyring. An operator must validate their completeness using the matching release and an isolated database, then plan a maintenance restore. Do not change version or scope markers to make an old archive appear compatible. See archive compatibility.

Configure the matching master key or keyring before attempting an encrypted archive restore. A missing or incorrect key prevents decryption. If you restore an independent SQL dump instead, the database may start successfully while connector secrets still fail to decrypt; those are different recovery paths.

Stop the service and restore a consistent copy of the installation together with its database, required volumes and external storage. The .env carries sensitive keys. Confirm the application version matches the restored schema before starting.

CI includes PostgreSQL 16 SQL restore checks and an encrypted application-archive restore drill using the restricted app_user role. These exercise representative fixtures and rollback controls; they do not prove every customer archive or your off-site recovery process.

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 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.

Native pre-update snapshots in the release candidate

Section titled “Native pre-update snapshots in the release candidate”

Before replacing staged program files, the native launcher copies the complete stopped PostgreSQL cluster, including WAL, into a private backups/pre-update-<timestamp>.pgdata directory. It verifies file hashes and refuses external tablespace links. Failure retains the current program and the staged update. A .partial directory is incomplete and cannot be restored.

For recovery, stop the service and database, preserve the failed state for diagnosis, restore the entire snapshot as .pgdata, and restore the matching previous program from .previous-version. Retain the original protected .env and PostgreSQL major version. Check health and retained data after startup. These snapshots are separate from encrypted application archives and SQL dumps; they need room for a complete cluster. Never copy an actively written cluster or restore only selected files from a physical snapshot.