SynapSynapDocs

Backups and restore

Where a pod's data lives, the backups it takes on its own, off-host snapshots, and how to restore.

For Self-hostersOpen-source podReviewed 2026-10-20

A pod backs itself up to its own disk every hour. That protects you from mistakes with Docker, not from losing the server. Set up off-host snapshots as soon as the pod holds anything you care about.

All commands run from the deploy directory:

cd /opt/synap/deploy

Where the data lives

DataWhereSurvives docker compose down -v?
PostgreSQL (your data, and Kratos accounts)Docker volume <project>_postgres_dataNo. That is why the dumps exist.
Hourly dumpsdeploy/backups/postgres/<UTC time>-auto/<database>.dump on the hostYes
Pre-update and manual dumpsdeploy/backups/postgres/<UTC time>-pre-update/… and -<label>/…Yes
Files (MinIO)Docker volume <project>_minio_data; included in off-host snapshotsNo, unless you have a snapshot
Search index (Typesense)Docker volume <project>_typesense_dataNo; it is rebuilt from PostgreSQL

<project> is the Compose project name, pinned as COMPOSE_PROJECT_NAME in deploy/.env. docker volume ls lists the volumes.

What the pod does on its own

The postgres-backup service:

  • dumps every database every hour (PG_BACKUP_INTERVAL_SECONDS, default 3600), reading each dump back before keeping it;
  • keeps the newest 6 dumps (PG_BACKUP_KEEP) plus one per day for 7 days (PG_BACKUP_KEEP_DAILY);
  • sets aside a dump of a database that suddenly became empty, marked SUSPECT, and raises an alarm instead of pruning or pushing anything;
  • pushes good dumps off-host once a repository is set up, and runs a restore drill every week;
  • reports itself unhealthy when there is no fresh dump or an alarm, a failed push or a failed drill.

Every synap update also takes a verified pre-update dump of every database before it runs migrations.

Set up off-host snapshots

Snapshots are encrypted on the pod with restic and sent to a repository you choose. Each snapshot holds every database dump, the files in MinIO, .env and the pod's state/ directory.

  1. Set the repository and its credentials:

    sudo synap config set BACKUP_REPOSITORY=rest:https://vault.example.com:8000/my-pod
    sudo synap config set BACKUP_RESTIC_REST_USERNAME=my-pod
    printf 'BACKUP_RESTIC_REST_PASSWORD=%s\n' '<password>' | sudo synap config set --stdin

    BACKUP_REPOSITORY also accepts s3:…, b2:<bucket>:<path> or a local path such as /mnt/backup. For S3 use BACKUP_AWS_ACCESS_KEY_ID, BACKUP_AWS_SECRET_ACCESS_KEY and BACKUP_AWS_DEFAULT_REGION; for Backblaze B2, BACKUP_B2_ACCOUNT_ID and BACKUP_B2_ACCOUNT_KEY. BACKUP_HEARTBEAT_URL is pinged after each successful push.

  2. Create the repository:

    sudo synap backup init

    It prints a recovery kit with the repository password, once, and asks you to type back its last six characters. Keep the kit in two places you control. Synap never has it, and without it the snapshots cannot be decrypted.

  3. Check it:

    sudo synap backup push      # take a snapshot now
    sudo synap backup status    # repository, last runs, alarms

The pod only ever adds snapshots; it never deletes them. Give it append-only credentials (a restic REST server with --append-only, or an S3 or B2 key without delete permission) and run retention where the delete-capable credentials live, for example:

restic forget --keep-hourly 24 --keep-daily 14 --keep-weekly 8 --keep-monthly 12 --prune

Commands

CommandWhat it does
synap backup [label]Dumps every database now, to backups/postgres/<time>-<label>/ (local only).
synap backup initCreates the off-host repository and prints the recovery kit.
synap backup pushDumps and pushes an encrypted snapshot now.
synap backup drill [snapshot]Restores a snapshot into a throwaway PostgreSQL and compares fingerprints.
synap backup statusRepository, last runs and alarms.
synap restore <backups/postgres/<dir>>Restores a local dump set. Stops writers first; replaces every database.
synap restore --from-snapshot <id|latest>Restores .env, state, databases and files from an off-host snapshot. Asks for the recovery-kit password, or takes --password-file <file>.

Both restore commands ask you to type yes before replacing anything.

Restore onto a new server

  1. Point the pod's DNS records at the new server, and install the pod there with the same --domain (self-host quickstart). The restore replaces its .env with the one in the snapshot.

  2. Set the same BACKUP_REPOSITORY and credentials with synap config set.

  3. Restore the latest snapshot:

    sudo synap restore --from-snapshot latest
  4. If the stack does not start because the server has no images yet, run sudo synap update; it keeps the restored .env. Then check with sudo synap health.

Large file uploads

Large files are uploaded to storage in parts. If the pod is stopped in the middle of an upload, the parts already sent stay in the bucket. The bundled MinIO removes stale parts by itself after 24 hours. On AWS S3, add a lifecycle rule AbortIncompleteMultipartUpload (for example after one day) to the bucket, or you pay for the leftovers; on other S3-compatible stores, check their lifecycle settings.

On this page