pgbr
Guides

Maintenance

Running the stack day to day, clearing history, wiping data, health checks, and upgrades.

The Settings page holds the destructive operations, plus storage config. Everything here is worth reading before clicking.

Clearing history

Two narrow, safe operations:

ActionDeletesKeeps
Clear restore historyYour restore job rowsEverything else
Clear migration historyYour migration job rowsEverything else

Both are scoped to your user and touch no artifacts — restores and migrations don't produce any. They're bookkeeping: clearing clutter, not deleting data.

There's no equivalent for backup history, because a backup row owns an artifact. Delete backups from the Backups page, where deletion removes the artifact too.

Wipe everything

The nuke option deletes, for your user:

  • Every database connection
  • Every schedule, and unregisters its cron scheduler in Redis
  • Every backup, restore, and migration job row
  • Every artifact those jobs referenced, resolved from the rows themselves rather than by wiping the bucket's prefixes

It keeps your user account and your storage settings — you're left with a working, empty install rather than a broken one. Another account's databases, schedules, history, and objects are untouched.

There is no undo, and pgbr has no backup of its own metadata. "Your data" is still all of it on a single-user install — which is the normal case.

The row deletions run in one transaction, so metadata is all-or-nothing. Object deletion happens after and is best-effort — if the store is unreachable, the rows are gone and the objects are orphaned.

If your bucket has versioning enabled, wiped objects are recoverable from the provider. That's one more reason to turn it on.

Health checks

GET /api/health returns { "status": "ok" } with no authentication. It's an unconditional liveness probe — it confirms the process is serving HTTP, not that Postgres, Redis, or the store are reachable.

healthcheck:
  test: ["CMD-SHELL", "wget -q -O - http://localhost:3000/api/health || exit 1"]
  interval: 10s
  timeout: 5s
  retries: 3

Don't read too much into a green health check. A dashboard with an unreachable Redis still returns ok. For real assurance, watch whether scheduled backups are completing — that exercises the whole path.

The worker has no health endpoint. It's a queue consumer with no HTTP surface; monitor it through its logs and through jobs completing.

Running the stack

Every one of these runs from your install directory — the one holding .env — and takes -f compose.prod.yaml:

GoalCommand
Start it, or apply changesdocker compose -f compose.prod.yaml up -d
Pause, keeping containersdocker compose -f compose.prod.yaml stop
Resume after a stopdocker compose -f compose.prod.yaml start
Stop and remove containers, keeping datadocker compose -f compose.prod.yaml down
Restart in placedocker compose -f compose.prod.yaml restart
Statusdocker compose -f compose.prod.yaml ps
Follow logsdocker compose -f compose.prod.yaml logs -f

stop and start are for a quick pause. down followed by up -d is what you want after editing .env or the compose file. Both keep every volume, so neither loses data.

down -v is the exception. The -v deletes the volumes — pgbr's metadata database and every backup artifact held in the SeaweedFS service. There is no undo, and nothing else on this list destroys anything.

Two mistakes that don't announce themselves as mistakes:

  • Run these from anywhere else and Compose never reads your .env, so it fails with required variable POSTGRES_PASSWORD is missing a value rather than anything about the directory you're in.
  • Drop the -f compose.prod.yaml inside a checkout of the repository and you are driving the development compose.yaml instead.

Upgrades

If you installed with the one-liner, re-run it from your install directory and it does all of this for you — it refreshes compose.prod.yaml, pulls both images, and restarts in the right order without touching a single value in your .env. Run it somewhere else and you get a second install rather than an upgrade:

curl -fsSL https://raw.githubusercontent.com/darseen/pgbr/main/scripts/install.sh | sh

By hand:

Pull matching tags

docker pull ghcr.io/darseen/pgbr-dashboard:latest
docker pull ghcr.io/darseen/pgbr-worker:latest

Both images ship from the same commit. Never run mismatched versions — they share a database schema and a queue payload format.

Restart the dashboard first

Its entrypoint runs pending database migrations before the server starts. Letting it go first means the schema is current before workers touch it.

Restart the worker

It reconciles schedules and re-checks the bucket on boot.

Migrations run automatically and are not reversible. Back up pgbr's own Postgres database before upgrading — it holds your connections, schedules, and history. Losing it doesn't lose your artifacts, but it loses everything that tells you what they are.

Restarting a worker mid-job is safe: BullMQ's stalled-job detection re-delivers to another worker, and processors are idempotent. It isn't free — a re-delivered backup re-runs pg_dump from the start.

Backing up pgbr itself

pgbr's metadata database is a normal PostgreSQL database. You can add it to pgbr as a connection and let it back itself up.

Circular, and it fails exactly when you need it: if pgbr's own database is lost, the backup of it is recorded in the database that's gone. Keep an independent dump of pgbr's Postgres somewhere pgbr doesn't manage — and keep ENCRYPTION_KEY with it, since the dump is useless without it.

Monitoring

Worth watching:

SignalWhy
Failed jobsJob History. A schedule failing silently is the main way backups quietly stop existing.
Backup sizesA sudden drop suggests a filter change or a partial dump.
Bucket growthRetention only applies through live schedules — manual backups accumulate forever.
Worker logsWhere reconciliation, bucket provisioning, and cleanup failures surface.
Redis persistenceQueue state is rebuildable, but in-flight jobs aren't.

The single best monitor for a backup system is a restore. Restore a recent backup into a scratch database on a schedule you actually keep. Everything else tells you a file exists; only a restore tells you it's a backup.

On this page