Skip to content
User Guide

Database Backup and Restore

MisterShell creates full PostgreSQL custom-format archives and stores them on the SFTP target configured in Settings → System → Config → Backup. The scheduled task and manual operator command use the same service and archive validation.

Database archives cover PostgreSQL data only. They do not cover recordings, the event store, mounted TLS files, or DB_ENCRYPTION_KEY. Back up those items separately. Keep the same DB_ENCRYPTION_KEY; without it, encrypted secrets in a restored database cannot be decrypted.

Scheduled backups

The built-in Database Backup task remains visible under Settings → System → Scheduled Tasks. You can enable it, set its interval, use Run Now, and inspect its execution logs like any other scheduled task. Scheduled execution is coordinated by the current Core leader.

Each run creates a file named like:

full_backup_20260823_101112123456_core-0.dump

The archive is uploaded only after PostgreSQL has produced a non-empty custom archive and MisterShell has read and validated it completely.

Manual backup and listing

Run these inside any Core container:

docker exec -it <core-container> msh show backups
docker exec <core-container> msh backup database --yes

To confirm mutating commands interactively, first open the console with docker exec -it <core-container> msh, then enter backup database. Manual backup and listing are allowed on any Core; unique filenames prevent Cores from overwriting one another.

Restore eligibility

In-product restore is supported only for a deployment configured as a single Core. It works with either embedded or external PostgreSQL; the difference is only the configured DATABASE_URL. Its database role must be allowed to force drop, create, own, and restore the target database.

TopologyBackup/listmsh restoreRecovery owner
Single Core + embedded DBScheduled/manual SFTPFile or SFTPMisterShell operator
Single Core + external DBScheduled/manual SFTPFile or SFTP; DB role needs drop/create/restoreMisterShell/DB operator
Multiple CoresLeader-scheduled; manual from any CoreRefusedPlatform admins shut all Cores and restore externally

The Core image ships PostgreSQL 17 client tools. An archive created by a newer client is never applied to an older server: MisterShell reads the dump version and checks the configured server before confirmation or quiescing. Use PostgreSQL 17 or a later compatible server for an external database if you want to use in-product backup and restore.

For every multi-Core deployment, msh restore refuses to run. Platform administrators must stop all Cores, restore the shared database with native PostgreSQL tooling, verify it, and then start the Cores again. Merely shutting down all but one Core does not make the deployment eligible.

Restore a local archive

Place a readable custom-format archive inside the Core container, then run:

docker exec <core-container> \
  msh restore database file /data/restore/archive.dump --yes

To confirm interactively, open msh first and enter the restore command without --yes. Before confirmation, MisterShell checks the PGDMP header, reads the archive table of contents, requires the alembic_version, app_settings, and cluster_state relations used by the restore checks, and renders the entire archive to /dev/null. The local source file is never deleted.

Restore an SFTP archive

List the available basenames, then restore one:

docker exec -it <core-container> msh show backups
docker exec <core-container> \
  msh restore database sftp full_backup_20260823_101112123456_core-0.dump --yes

MisterShell first downloads the file to a private 0600 file under /data/restore-staging, then runs the exact same validation and restore engine as local-file mode. This preliminary fetch requires the current database and its backup settings to remain readable. An aborted or invalid preflight removes the staging file.

When a new SFTP restore starts, MisterShell removes abandoned staging downloads older than seven days. Recent files are retained so a failed restore can be retried from its reported local path.

What happens during restore

After validation and explicit confirmation, MisterShell verifies that the command is running through docker exec in the expected Core container. It suspends the Core application, force-drops and recreates the configured database from template0, restores with fail-fast PostgreSQL options, then verifies UTF-8 encoding, the Alembic revision, and required application relations.

On success, the command expires the restored leadership lease, prints and audits the result, clears the cluster liveness marker so startup performs cold initialization, then stops the Core. A container restart policy such as unless-stopped starts it again; otherwise, start the container yourself.

If a destructive step fails, the Core deliberately remains suspended so it cannot serve a partial database. Do not restart it. For an SFTP restore, the error includes the preserved local staging path. Open a new docker exec session, correct the database/archive problem, and retry with:

restore database file <preserved-path>

SFTP trust and archive security

MisterShell uses the configured SFTP username and password but does not verify or pin the SFTP server host key. Platform administrators are responsible for a trusted endpoint, DNS, routing, and network path. PostgreSQL restore executes content supplied by the archive, so restore only archives whose source you trust. MisterShell validates readability and product identity; it does not establish archive authenticity.