Skip to content

Back up and restore

How-to guide
For:
Server operators

Back up ReputeCast with pg_dump, the secret key and the files folder: a restore needs all three, and the database alone is not enough.

Part What it holds Where it is
PostgreSQL database Everything else: workspaces, contacts, campaigns, uploaded images, the job queue, the audit log, and every stored credential in encrypted form. The database in database.url.
Secret key The AES-256-GCM key that encrypts provider credentials, OIDC client secrets, HostRepute tokens and authenticator (TOTP) seeds in the database. REPUTECAST_SECRETS__KEY when you set it; otherwise the key file secrets.key_file: /var/lib/reputecast/secret.key in Docker, data/secret.key for the binary (relative to the directory ReputeCast starts in).
Files folder Digital products’ files and lead magnets, which are too large for the database. files.dir; by default a files folder next to the key file (/var/lib/reputecast/files in Docker). It appears once someone uploads a file.

Keep your configuration too: the .env file or shell variables you start Docker Compose with, or your YAML config file and environment file for the binary. The configuration reference lists every setting.

  • Shell access to the server, and the Docker Compose project directory (the one with docker-compose.yml) or the binary’s environment file.
  • For the binary: pg_dump, pg_restore and psql of the same PostgreSQL major version as your server, or newer.
  • Enough disk space outside the data volume for the dumps.

The shipped compose file names the project reputecast, so its volumes are reputecast_pgdata and reputecast_appdata. The app volume holds the key file and the files folder.

  1. Dump the database from inside the postgres container, so client and server versions always match. -T turns off the terminal, which would otherwise corrupt the binary dump:

    Terminal window
    docker compose exec -T postgres pg_dump -U reputecast -d reputecast -Fc > reputecast-$(date +%F).dump

    pg_dump takes a consistent snapshot while ReputeCast keeps running.

  2. Archive the app volume (secret key and files folder) with a short-lived container. Any image with tar works:

    Terminal
    docker run --rm -v reputecast_appdata:/data -v "$PWD":/backup alpine:3.22 \
    tar czf /backup/appdata-$(date +%F).tar.gz -C /data .

    tar keeps the owner (user 65532, the image’s non-root user) and the 0600 mode of secret.key.

  3. If you set REPUTECAST_SECRETS__KEY yourself instead of using the key file, store that value with your configuration backup.

  4. Copy the dump and the archive off the server.

Restore the database before ReputeCast starts. The Docker image runs with --auto-install: started on an empty database, it creates a new first Owner, which you don’t want on top of a restore.

  1. Stop the app and keep PostgreSQL running. On a new server, start only PostgreSQL:

    Terminal
    docker compose stop app
    docker compose up -d --wait postgres
  2. Replace the database with an empty one:

    Terminal
    docker compose exec -T postgres dropdb -U reputecast --force --if-exists reputecast
    docker compose exec -T postgres psql -U reputecast -d postgres -c 'CREATE DATABASE reputecast'
  3. On a new PostgreSQL server, create the role that SQL segments run as. pg_dump copies one database, not the server’s roles, and without this role the restore stops with role "reputecast_segments" does not exist:

    Terminal
    docker compose exec -T postgres psql -U reputecast -d postgres \
    -c 'CREATE ROLE reputecast_segments NOLOGIN NOINHERIT' \
    -c 'GRANT reputecast_segments TO reputecast'
  4. Restore the dump:

    Terminal window
    docker compose exec -T postgres pg_restore -U reputecast -d reputecast --exit-on-error < reputecast-2026-10-22.dump
  5. Put the secret key and files back into the app volume. docker compose create app creates the container and its volume without starting it:

    Terminal
    docker compose create app
    docker run --rm -v reputecast_appdata:/data -v "$PWD":/backup alpine:3.22 \
    tar xzf /backup/appdata-2026-10-22.tar.gz -C /data
  6. Start ReputeCast:

    Terminal window
    docker compose up -d

    If the image is newer than the backup, it applies the pending migrations at start.

  • curl -s http://localhost:8080/readyz answers ready. See health checks, metrics and logs.
  • The app logs don’t contain generated a new secret key. If they do, ReputeCast didn’t find the restored key: stop it, put the key back and start it again.
  • Sign in with your password and authenticator app. A working authenticator sign-in proves the key matches the database.
  • Open Sending providers in a workspace: connected sending providers keep their status instead of asking for credentials.

Test a restore before you need one: restore the latest backup into a second Compose project on another port (for example docker compose -p reputecast-restore-test with REPUTECAST_PORT=8090) and sign in there.

  • role "reputecast_segments" does not exist during pg_restore: the server is new. Create the role (step 3 of the restore), recreate the empty database and restore again.
  • Authenticator sign-in fails with secrets: cannot decrypt value: the database was restored without its key, or with the wrong one. Put the original key back. If it is lost, people sign in with a recovery code or passkey, an instance admin removes their authenticator with reputecast user reset-2fa, and each workspace enters its provider credentials again.
  • A new Owner with a temporary password appears in the logs: the app started before the database was restored. Stop it, recreate the database and restore again.
  • pg_restore: error: unsupported version or similar: your pg_restore is older than the pg_dump that wrote the file. Run the restore inside the postgres container, or install a newer client.