Deploying the panel
Esta página aún no está disponible en tu idioma.
The enterprise panel (cloud/api, serving the dashboard in cloud/dashboard) is a small,
self-hostable Node service. It is built on Node built-ins — node:http, node:crypto
(Ed25519) and node:sqlite — with one optional runtime dependency: the pg driver, loaded
only when Postgres is selected.
Requirements
Section titled “Requirements”- Node ≥ 22.5 (developed on 26). The default SQLite mode runs and tests with just
node, no install step. pnpm install(for thepgdriver) only if you use Postgres locally; the Docker image installs it.
just panel-run # or: cd cloud/api && node src/index.tsOn boot the panel loads (or generates) its Ed25519 signing key, seeds the default catalog, and prints the two values daemons need to connect:
CHRONOS_PANEL_URL=http://127.0.0.1:8787CHRONOS_PANEL_PUBKEY=<64-hex public key>Storage
Section titled “Storage”One storage interface, two backends:
- SQLite (default) — zero dependencies, single-tenant. The database file lives at
PANEL_DB(defaults topanel.db). - Postgres / Neon — set
DATABASE_URL(for Neon, the connection string with?sslmode=require); it takes precedence overPANEL_DB. The schema is created on boot, and the signing key persists in the database, so daemons keep verifying across restarts and redeploys.
Signing key persistence — read this before production
Section titled “Signing key persistence — read this before production”The panel signs every catalog, context and pack bundle with its Ed25519 private key, and every daemon pins the corresponding public key at login. If the key is regenerated — for example, a redeploy without persistent storage — every daemon that pinned the old public key stops trusting the panel and must reconnect.
So the key must survive redeploys:
- In production, provide it via
PANEL_SIGNING_KEYfrom a KMS or secret manager. Never commit it, never store it in cleartext. - With Postgres, the key persists in the database automatically.
- With SQLite, put
PANEL_DBon a mounted volume (the Docker image defaults to/app/data/panel.dbfor exactly this reason).
Planned rotation is different from key loss: rotating from the dashboard’s Keys tab keeps previous keys in the trusted-key set, so live daemons keep verifying.
Admin bootstrap
Section titled “Admin bootstrap”Set PANEL_ADMIN_PASSWORD (and optionally PANEL_ADMIN_IDENTITY, default admin@corp).
At boot the panel creates — or password-resets — the admin account, so a fresh deployment
is administrable without touching the database. From there, create real users in the
dashboard (one-time passwords, scrypt-hashed) — see the
Administrator guide.
PANEL_SEED_PASSWORD gives the demo accounts credentials for local development and tests
only; without it they cannot sign in.
Environment reference
Section titled “Environment reference”| Variable | Purpose |
|---|---|
PANEL_DB | SQLite database path (default panel.db) |
DATABASE_URL | Postgres/Neon connection string; wins over PANEL_DB |
PANEL_SIGNING_KEY | Ed25519 signing key (production: from a KMS/secret manager) |
PANEL_ADMIN_PASSWORD | bootstraps/resets the admin account at boot |
PANEL_ADMIN_IDENTITY | admin identity (default admin@corp) |
PANEL_SEED_PASSWORD | dev/test only: credentials for the demo accounts |
Docker
Section titled “Docker”cloud/Dockerfile builds a production image on node:24-slim. The build context is
cloud/ so the API can serve its sibling dashboard as static files. It installs runtime
dependencies only (pg), listens on port 8787, and sets PANEL_DB=/app/data/panel.db —
mount a volume at /app/data so the signing key and catalog survive redeploys.
cd clouddocker build -t chronos-panel .docker run -p 8787:8787 \ -v panel-data:/app/data \ -e PANEL_ADMIN_PASSWORD=<bootstrapPassword> \ chronos-panelRailway
Section titled “Railway”The panel deploys to Railway from the same Dockerfile (build context cloud/). Two points
matter:
- Persistence. Either attach a Railway volume at
/app/data(SQLite), or setDATABASE_URLto a Postgres/Neon instance — with Postgres the signing key persists in the database, so redeploys are safe by default. - Variables. Set
PANEL_ADMIN_PASSWORD(andPANEL_SIGNING_KEYif you manage the key externally) as service variables.
Connect a daemon
Section titled “Connect a daemon”Developers normally connect with chronos login (device flow; the bearer lives in the OS
keychain and the panel keys are pinned at login). For CI or ops, environment variables take
precedence:
export CHRONOS_PANEL_URL=https://<yourPanelHost>export CHRONOS_PANEL_PUBKEY=<hexPublicKey> # the daemon pins the PUBLIC key onlyexport CHRONOS_IDENTITY=<userEmail>export CHRONOS_TEAMS=<teamA>,<teamB>just run-daemonWith CHRONOS_PANEL_URL unset the daemon runs offline with no governed MCPs — CI never
needs the panel.
just panel-test # node --test (SQLite suite; the pg suite self-skips)TEST_DATABASE_URL=postgres://<connectionString> just panel-test # also runs the Postgres suiteThe Postgres suite drops the panel tables — point TEST_DATABASE_URL at throwaway
databases only.