Skip to content

Backup, restore, and upgrades

Back up before migrations, retention changes, or server upgrades. Keep backups private: account files contain password hashes, authentication state, IRC credentials, and encryption keys.

Persistent data inventory

Back up the entire active RELAY_HOME, plus external database data and files referenced by absolute paths.

Location Contents
config.yaml, admin-overrides.json File configuration and higher-priority administrator settings
users/ Accounts, networks, preferences, sessions, local MFA state, encryption keys, and current-master saved messages/notes
logs/ Per-account *.sqlite3 history and text logs
uploads/ Uploaded files, metadata, avatars and experimental DCC files/indexes
message-shares/, shortlinks.sqlite3 Shared message snapshots and redirect records
pastes/ Pastebin text and expiration records
certificates/ IRC client certificates used for SASL EXTERNAL
vapid.json Web Push signing keys
packages/, themes/ Installed packages, package source manifest, custom themes
External PostgreSQL Structured history and, on current master after migration, short links

storage/ is prefetched-media cache; Relay clears it at startup/shutdown when cache storage is enabled. Also retain the exact image digest or binary and public/ assets, Compose/service definitions, environment settings and externally stored TLS/SMTP/OIDC secrets needed to reproduce the deployment.

Consistent SQLite backup

The simplest complete snapshot is taken while Relay is stopped. For the bind-mount Compose example, from the Compose directory:

mkdir -p backups
chmod 700 backups
docker compose stop relay
tar -czpf "backups/relay-data-$(date +%Y%m%d-%H%M%S).tar.gz" data
docker compose start relay

Use an account that can read every file; confirm tar succeeds before restarting. Preserve the entire directory, including any SQLite -wal/-shm files, instead of copying only the main database. Named volumes require a volume-aware backup job with the service stopped; the command above only backs up ./data.

For an individual live database, use SQLite's backup API (the sqlite3 shell's .backup) or VACUUM INTO; a filesystem copy of an active database is not a consistent backup. A per-database snapshot does not synchronize account JSON, uploads, and other databases, so quiesce Relay for a complete restore point. See SQLite backup methods.

PostgreSQL backup

Stop Relay to keep its filesystem state aligned with the database dump, then archive RELAY_HOME as above and dump the Relay database. Configure a protected libpq service entry named relay-backup with the correct database, host and user (and use a protected password file):

pg_dump --dbname='service=relay-backup' --format=custom --file=backups/relay.pgdump

pg_dump gives a consistent database snapshot. Save required roles separately through your database administration process; a single-database dump does not contain cluster roles. Use a compatible client version. See PostgreSQL SQL dumps.

Restore into isolation

  1. Create a fresh test data directory/volume and extract the backup there, preserving ownership and permissions. Never extract over a running production home.
  2. For PostgreSQL, create an empty test database and restore with pg_restore --exit-on-error --no-owner --dbname='service=relay-restore' backups/relay.pgdump. The relay-restore service must point to the isolated database. Arrange appropriate ownership for the test Relay role.
  3. Inspect both config.yaml and admin-overrides.json in the copy. Replace production database URLs and integration settings. Block outbound network access before startup: restored users automatically reconnect to saved IRC networks. A loopback web listener alone does not prevent those outbound connections.
  4. Start the matching Relay version using the restored home and a loopback listener. Check each SQLite database with PRAGMA integrity_check;, then verify login, representative old history/search, upload access, shares, and settings. Use synthetic accounts for routine restore drills; protect real restored credentials if testing a production backup.
  5. Stop the test instance and record counts, sample timestamps, missing files, and the tested version. Only schedule production restoration after this check passes.

Upgrades and rollback

Record the old image digest/version and make a tested backup first. Choose the target release from the Download page, set RELAY_IMAGE to its full versioned image, then:

docker compose pull relay
docker compose up -d --no-deps relay
docker compose logs --tail=100 relay

Compose recreates a service when its image/configuration changes while retaining mounted volumes; see docker compose up. Verify login, /ws, existing IRC connections, history/search, uploads and administrator settings. relay upgrade only updates installed packages.

Rollback needs matching data

Database migrations can make new data incompatible with an older binary. Keep the old image and a complete pre-upgrade filesystem/database backup. Rollback may lose messages and account changes made since that backup; assess the loss before restoring it.

If rollback is needed, stop the new version, preserve a separate copy of its current data, restore the matching pre-upgrade home and database, select the old image, and start it. Do not run both versions against the same writable data, and do not delete named volumes as part of an upgrade.