Operating a hub
For the people who run a hub: the official hub, or a self-hosted one. The hub is a Next.js app with a Postgres database, in hub/ of the repository.
Configuration#
| Variable | Required | Meaning |
|---|---|---|
HUB_ENV |
Yes | development, test, or production. Outside production the hub only accepts the databases agentwarden_hub_dev and agentwarden_hub_test. |
HUB_PUBLIC_URL |
Yes | The address sites and people use, for example https://hub.agentwarden.com. |
DATABASE_URL |
Yes | postgres:// URL. |
HUB_SIGNING_KEY |
Yes | 64 hex characters from npx tsx bin/keygen.ts, which also prints the public key. Keep it secret. |
NEXT_SERVER_ACTIONS_ENCRYPTION_KEY |
With more than one instance | A stable base64 key shared by every instance. |
HUB_MAIL_MOCK, HUB_SMTP_URL, HUB_MAIL_FROM |
For real email | Mail goes to the outbox table unless HUB_MAIL_MOCK=0 and both SMTP settings are set. |
DODO_MOCK, DODO_API_KEY, DODO_WEBHOOK_SECRET, DODO_ENVIRONMENT, DODO_PRODUCT_AGENCY_<25|UNLIMITED>_<MONTHLY|ANNUAL>, DODO_PRODUCT_PRO_<MONTHLY|ANNUAL> |
For billing and Pro licenses | Billing is mocked unless DODO_MOCK=0 with the key, the webhook secret, and at least one Agency product. Pro license checks are mocked until a Pro product is set with DODO_MOCK=0. Production refuses both mocks. Point Dodo's webhook at /api/webhooks/dodo. |
Sites trust the official hub keys built into the plugin. For a self-hosted hub, add its public key on each site with define( 'AGENTWARDEN_HUB_TRUSTED_KEYS', '<base64 key>' ); and its address with define( 'AGENTWARDEN_HUB_URL', 'https://hub.example.com' );.
Processes#
The image runs one of:
web: applies pending migrations under a lock, then serves on port 3000./api/healthreports whether the database is reachable.scheduler: sends due client digests at the start of every hour.migrate up|down [steps]|statusandset-plan, as one-off commands.
Deploying#
hub/bin/deploy.sh local # tests, then Docker Compose: hub on http://127.0.0.1:3295, Postgres, scheduler
hub/bin/deploy.sh local down # stop it; the database volume is kept
hub/bin/deploy.sh fly # tests, then fly deploy with fly.toml (needs flyctl and FLY_API_TOKEN)
On Fly, migrations run as the release command before new machines start. Vercel has no release command, so run migrations before deploying there (GETTING_ENV_VARS.md in the repository, part 5).
Enterprise plans#
npx tsx bin/set-plan.ts <team-id> enterprise <50|250|unlimited> --by "you@agentwarden.com"
npx tsx bin/set-plan.ts <team-id> none --by "you@agentwarden.com"
In the container: bin/docker-entrypoint.sh set-plan <team-id> enterprise 250 --by "...". Webhooks never change a plan set this way.
Backups and restores#
HUB_ENV=production hub/bin/backup.sh "$DATABASE_URL" /backups 14
HUB_ENV=production hub/bin/restore.sh /backups/agentwarden-hub-<db>-<time>.dump "$EMPTY_DATABASE_URL"
backup.shwrites apg_dumpcustom-format file and a.sha256beside it, and keeps the newest 14 (or the count you give).restore.shrefuses a backup that does not match its checksum and a database that already has tables, and restores in one transaction.- Both need PostgreSQL client tools at least as new as the server; set
PG_BINto their directory if the ones onPATHare older. hub/bin/backup-restore-test.shproves the round trip on the test database, table by table. It runs in every hub check and in CI.
Run a restore drill before launch and after any change to the database setup.
Checks#
bin/hub-check.sh runs the type check, lint, unit tests against Postgres, the migration round trip, the production build, browser tests, ShellCheck, and the backup and restore round trip.