chmonitor
Deployment

Cloudflare Workers

Deploy chmonitor to Cloudflare Workers for globally distributed, serverless hosting with D1 and Cron Trigger support.

Deploy chmonitor to Cloudflare Workers — best for globally cached, serverless hosting with no servers to manage.

The dashboard app (apps/dashboard) uses the @cloudflare/vite-plugin to build a native Cloudflare Workers bundle — no OpenNext adapter required. The deploy script is just pnpm run build && wrangler deploy.

Prerequisites

What you need

  • Cloudflare account
  • pnpm installed locally or in CI
  • CLOUDFLARE_API_TOKEN with Workers deploy permissions (or run wrangler login for OAuth)

One-click deploy

Deploy to Cloudflare

This deploys the apps/dashboard worker. Set the three ClickHouse vars when prompted. Full list: Environment variables.

Setup

Clone and install

git clone https://github.com/chmonitor/chmonitor.git
cd chmonitor/apps/dashboard
pnpm install

Set ClickHouse secrets

wrangler secret put CLICKHOUSE_HOST
wrangler secret put CLICKHOUSE_PASSWORD

Build and deploy

pnpm run cf:deploy   # vite build → wrangler deploy

Open your Worker URL

Open your Workers URL or set a custom domain in the Cloudflare dashboard.

Verify

Open your Workers URL. To confirm from the shell, hit the readiness endpoint:

curl -sf https://<your-worker-url>/api/healthz && echo OK

How configuration works on Cloudflare

Build-time vs runtime vars

There are two kinds of variables — mixing them up is the most common source of bugs.

KindWhere to setWho reads itExample
Build-timeCI / shell before pnpm run buildBrowser (derived VITE_*)CHM_AUTH_PROVIDER, CHM_CLERK_PUBLISHABLE_KEY
Runtime.env.production (hosted) or wrangler secret putWorkerCLICKHOUSE_HOST, LLM_API_KEY, CLERK_SECRET_KEY

Set CHM_* once. Do not also set VITE_*. Hosted dashboard wrangler.toml has no [vars] block — edit .env.production.

One canonical name

You usually don't set VITE_* directly. Set the canonical CHM_* name (e.g. CHM_AUTH_PROVIDER) in the build environment and vite.config.ts derives the matching VITE_*. A dual-surface setting must be present at build time (so the VITE_* inlines) and as a runtime [var] (so the server reads CHM_*) — same name, both places. See One canonical name per setting.

Runtime Worker vars (wrangler.toml [vars] and secrets) are never visible in the browser.

Secrets

wrangler secret put CLICKHOUSE_HOST
wrangler secret put CLICKHOUSE_PASSWORD

Optional secrets (CLERK_SECRET_KEY, ANYROUTER_API_KEY, CRON_SECRET, …): see Environment variables.

Redeploy after secret changes

After wrangler secret put, redeploy so the Worker picks up the change: pnpm run cf:deploy.

Configure

Required: CLICKHOUSE_HOST, CLICKHOUSE_USER, CLICKHOUSE_PASSWORD.

Template: apps/dashboard/.env.example. Full names: Environment variables. Auth: Authentication. Conversations: Conversation storage.

Deploy

pnpm run cf:deploy

This runs: vite build (produces the Cloudflare Workers bundle) → wrangler deploy.

CI (GitHub Actions): push to main triggers .github/workflows/cloudflare.yml. Set CLOUDFLARE_API_TOKEN as a repository secret, plus CLICKHOUSE_*, and any canonical build-time vars (e.g. CHM_AUTH_PROVIDER, CHM_CLERK_PUBLISHABLE_KEY — the client VITE_* derive from them).

This repo's hosted deploy uses .env.production

Dashboard wrangler.toml declares no [vars]. Non-secret hosted config lives in apps/dashboard/.env.production (+ .env.preview). Edit that file — do not re-add [vars].

Preview locally

pnpm run cf:preview

Cloudflare bindings

The app uses these Cloudflare resources (configured in wrangler.toml):

BindingTypePurpose
CHM_CLOUD_D1D1 DatabaseConversation history (optional)
AGENT_CONVERSATIONS_DODurable ObjectConversation history via Durable Objects (optional)

The TanStack Start build via @cloudflare/vite-plugin does not require KV, R2, or cache-tag bindings. Only conversation-store bindings need to be added if you enable server-side persistence.

Upgrading

Rebuild and deploy

pnpm run cf:deploy

Worker secrets persist across deploys; you only need to re-run wrangler secret put when a value changes.

For breaking changes between major versions, see Migrating to v0.3.

Troubleshooting

On this page