Self-host on Cloudflare
Operate the API, dashboard, and public blog on your own Cloudflare D1 and R2 resources.
Set:
SELF_HOSTED=true
Self-host mode disables hosted Polar gates and workspace API quotas while preserving scoped tokens, media safety limits, activity, and versions.
Topology
- The API and dashboard Worker (
wrangler.jsonc) runs Hono, Better Auth, REST, MCP, media writes, and the static dashboard SPA. - The OG Worker (
wrangler.og.jsonc, namevibecms-og) renders share-card images. - The public Worker (
wrangler.public.jsonc) runs Astro SSR for blog pages, feeds, search, Markdown responses, and media reads. It reaches the API through theAPIservice binding and the OG Worker through theOGservice binding pointing atvibecms-og. - The API and public Workers share one D1 database and one R2 bucket. The OG Worker binds neither; the public Worker reaches it only through the
OGservice binding.
Required secrets
pnpm --filter @vc/api exec wrangler secret put BETTER_AUTH_SECRET --config ../../wrangler.jsonc
pnpm --filter @vc/api exec wrangler secret put TOKEN_PEPPER --config ../../wrangler.jsonc
Generate each value with:
openssl rand -hex 32
Production OTP delivery also requires a configured EMAIL binding and sender domain.
Scheduled jobs
The API Worker’s wrangler.jsonc declares three cron triggers — three of the five a Workers Free account allows: 17 2 * * * runs the daily analytics rollup and the subpath location re-check, */15 * * * * runs media reconciliation, and * * * * * publishes due scheduled posts. Removing the daily trigger stops history rollups and location re-checks; scheduled publishing depends on the every-minute trigger.
Optional analytics and AI
Blog analytics turn on when the public Worker has an analytics_engine_datasets binding named ANALYTICS and both Workers set ANALYTICS_ACCOUNT_ID, ANALYTICS_DATASET, and ANALYTICS_API_TOKEN (see docs/self-hosting.md). Without them, analytics collects nothing.
AI SEO reviews need a Workers AI binding named AI on the API Worker; SEO_REVIEW_MODEL picks the model. Without the binding, AI review requests return AI_UNAVAILABLE and deterministic SEO checks still work.
Deploy
After replacing the placeholder resource IDs, names, service target, and hosts in the root Wrangler files:
pnpm install
pnpm typecheck
pnpm test
pnpm build:self-host
pnpm deploy
pnpm deploy builds all three Workers, applies D1 migrations, then deploys them in order: API, OG, public. The public Worker’s OG service binding targets the OG Worker by name (vibecms-og by default) — keep that name in sync if you rename it in wrangler.og.jsonc.
For the full operator contract, resource list, email setup, and deployment caveats, see docs/self-hosting.md.