Backup & Restore
For the self-host compose stack. PostgreSQL holds the application state. The Context Fabric holds bounded evidence copies that may no longer be reproducible after upstream content changes or is erased.
What to back up
| Data | Where | Priority |
|---|---|---|
| PostgreSQL database | postgresql-data volume | Everything. Accounts, workspaces, observations, feedback, encrypted provider tokens, JWT signing keys. |
.env | /opt/hephaestus/docker/self-host/.env | Equal priority. HEPHAESTUS_SECURITY_ENCRYPTION_KEY encrypts the tokens inside the database backup — a database backup without the key is partially unreadable (all stored provider credentials are lost, and all sessions invalidate). |
| TLS certificates | ./letsencrypt/ | Optional — Let's Encrypt re-issues on first boot (rate limits permitting). |
| Context Fabric | git-repos volume | Back up when replayable evidence is required. Skipping it discards repository clones and bounded replay/CAS content; durable job provenance remains in PostgreSQL, but the exact source bytes may be unrecoverable. |
| NATS JetStream | nats-data volume | Skip — a transient event buffer, not a source of truth. |
Backup
Logical dump while everything runs (safe — Postgres MVCC gives a consistent snapshot):
cd /opt/hephaestus/docker/self-host
docker compose exec -T postgres pg_dump -U root -Fc hephaestus \
> hephaestus-$(date +%F).dump
cp .env hephaestus-$(date +%F).env
Ship both files off the host, encrypted. Cron it daily; test-restore it at least once (below).
Restore
On a fresh host, complete install steps 1–2 first, restoring the saved .env (same
POSTGRES_PASSWORD, same HEPHAESTUS_SECURITY_ENCRYPTION_KEY — non-negotiable). Then:
cd /opt/hephaestus/docker/self-host
docker compose up -d postgres # database only
docker compose stop application-server webhook-server 2>/dev/null || true
docker compose exec -T postgres dropdb -U root --if-exists hephaestus
docker compose exec -T postgres createdb -U root hephaestus
docker compose exec -T postgres pg_restore -U root -d hephaestus --no-owner \
< hephaestus-YYYY-MM-DD.dump
docker compose up -d # full stack
Verify: sign in, open a workspace, check recent activity is present up to the backup timestamp.
After a point-in-time restore
- Sessions: users signed in after the backup was taken must sign in again. If the
restored
jwt_signing_keytable is unusable, truncate it and restart — a fresh key is auto-seeded and everyone re-logs-in. No data loss beyond sessions. - NATS JetStream: the stream on
nats-datamay hold events the restored database has already processed (or never saw). Webhook ingest deduplicates by delivery id and idempotency keys, so replays are absorbed on ingest; the end-to-end redelivery-safety drill (including whether to reset consumers after a restore) is part of #1370. The conservative option after a restore from an old backup:docker compose down,docker volume rm hephaestus_nats-data,docker compose up -d— events in the gap are re-fetched by the scheduled sync. - Restore into an older app version: don't. Restore with the same
IMAGE_TAGthe backup was taken from, then upgrade.