.env, config overlay, .key.yaml files and compose.override.yaml together in protected storage. If uploads use an external bucket, back up that bucket separately.
Make and check a backup
Run the script while thepg service is running, and copy its output off the host:
pg_dump -Fc, checks that pg_restore --list can read the archive’s table of contents, and archives the local upload volume if it exists. This detects an empty or unreadable archive at that point; it does not prove that every table and file can be restored. A restore rehearsal is the stronger check.
For a database rehearsal, choose the dump to test and run these commands in the checkout. They create a new scratch database; the running application keeps using its existing database:
tar tzf backups/mirobody-uploads-YYYYMMDD-HHMMSS.tar.gz after replacing the filename. An external bucket needs its own restore drill.
For a full rehearsal, use a protected, isolated test host: clone the code version recorded with the backup, configure it as a fresh server deployment without public access, and copy over the backup plus its matching keys and configuration. Start its empty stack, then run Recover a deployment on that test host, including the upload archive or external bucket restore. Sign in, open a representative restored record and an uploaded file, and check the health response. Keep production’s volumes and network out of this test. The scratch-database check above is a faster archive check; it does not replace this full rehearsal.
Recover a deployment
Stop application writes but leave Postgres running. Replace the example dump name with the backup you selected:holistic_db_restored already exists. Set PG_DBNAME: holistic_db_restored in the active config.prod.yaml (or the overlay selected by ENV). Restore the matching encryption keys and configuration before starting the app; encrypted records are unreadable under newly generated keys.
If files were stored locally, find the actual upload volume name with docker volume ls. A checkout named mirobody normally has mirobody_mirobody_upload. Confirm the named volume already exists before restoring; otherwise docker run -v would silently create an empty one. Restore the matching archive into that volume:
.env, and encryption keys match the restored data. Then start the app: