Cloudflare Workers
Copy page
This is the edge self-host path: the same open-source server as Docker/plandesk serve, packaged for Cloudflare Workers. You own the database (Turso/libSQL); the Worker never auto-migrates. Auth is better-auth — browser sign-in via optional GitHub social, CLI/agent via paste-a-token (plandesk login).
Prerequisites
Section titled “Prerequisites”- A Turso (or other libSQL) database and auth token
- Cloudflare account + Wrangler (
npm i -g wrangleror use the package-local binary) - Optional: a GitHub OAuth App if you want dashboard “Sign in with GitHub”
- An R2 bucket for file blobs (or S3-compatible credentials pointing at R2)
1. Provision the database and migrate
Section titled “1. Provision the database and migrate”You own the schema. Apply domain migrations and better-auth tables once (and again on upgrades):
plandesk migrate \ --db "libsql://your-db.turso.io" \ --db-token "<token>"The Worker does not run migrations at request time. Skipping this step means empty/missing tables and opaque runtime failures.
2. GitHub OAuth app (optional)
Section titled “2. GitHub OAuth app (optional)”GitHub is optional (REQ-20). Without it, the dashboard uses token entry only; CLI still uses plandesk login paste-a-token.
If you want social sign-in:
-
Create a GitHub OAuth App.
-
Set the Authorization callback URL to:
<PLANDESK_BASE_URL>/api/auth/callback/githubExample:
https://plandesk-api.your-subdomain.workers.dev/api/auth/callback/githubThis is better-auth’s callback route. Do not use the removed path
/api/v1/auth/github/callback. -
Note the client id and client secret for Wrangler secrets below.
3. Configure secrets and public URL
Section titled “3. Configure secrets and public URL”From packages/plandesk-worker (or your deploy checkout that contains wrangler.toml):
# Databasewrangler secret put PLANDESK_DB_URLwrangler secret put PLANDESK_DB_TOKEN
# better-auth (required on Workers — non-loopback bind has no default-org trust)wrangler secret put PLANDESK_BETTER_AUTH_SECRET # long random string; keep stable across deploys
# Object storage — no secrets needed: the native R2 binding (`FILES` in# wrangler.toml `[[r2_buckets]]`) is used automatically when present. Just# create the bucket and keep the binding:# wrangler r2 bucket create plandesk-files# S3-compatible credentials are only a fallback for non-R2 object stores:# wrangler secret put PLANDESK_S3_BUCKET# wrangler secret put PLANDESK_S3_REGION# wrangler secret put PLANDESK_S3_ACCESS_KEY_ID# wrangler secret put PLANDESK_S3_SECRET_ACCESS_KEY# wrangler secret put PLANDESK_S3_ENDPOINT# wrangler secret put PLANDESK_AUTH_PASSWORD # optional shared-secret gate
# Optional GitHub social (all-or-nothing)wrangler secret put PLANDESK_GITHUB_CLIENT_IDwrangler secret put PLANDESK_GITHUB_CLIENT_SECRET# Still required by githubConfigFromEnv for githubEnabled; set to the better-auth callback:wrangler secret put PLANDESK_GITHUB_CALLBACK_URL# value: https://<your-worker>/api/auth/callback/githubSet the public origin (not a secret) in wrangler.toml [vars]:
[vars]PLANDESK_BASE_URL = "https://plandesk-api.your-subdomain.workers.dev"PLANDESK_BASE_URL is better-auth’s baseURL (OAuth redirect + cookies). If unset, the Worker falls back to the request URL origin — set it explicitly for stable OAuth.
Misconfiguration: without PLANDESK_BETTER_AUTH_SECRET, API requests return 500 with a clear misconfigured message naming the secret — not a silent 401 storm.
4. Build the web SPA into the package
Section titled “4. Build the web SPA into the package”The Workers entry lives in packages/plandesk-worker — a deploy-only package that composes the REST API (@plandesk/api) with the MCP server (@plandesk/mcp), so a hosted board serves agent tools at /mcp as well as the API. It reads the SPA from packages/plandesk-api/web ([assets] in its wrangler.toml). Build the web app and copy it there (the API package’s prepack script does this when publishing; for a local deploy):
# 1. Build the SPA (outputs to apps/plandesk-web/dist)pnpm --filter plandesk-web build
# 2. Copy it into the API package's web/ (wrangler [assets] serves it)pnpm --filter @plandesk/api run prepackThe prepack step copies apps/plandesk-web/dist → packages/plandesk-api/web. Confirm packages/plandesk-api/web/index.html exists before deploying.
5. Deploy
Section titled “5. Deploy”cd packages/plandesk-workerwrangler deployOpen PLANDESK_BASE_URL. Sign in with GitHub (if configured) or mint a CLI token from a signed-in dashboard session and run:
plandesk login --server "$PLANDESK_BASE_URL"plandesk connect --to <org> [--project <id|name>]Agents never log in themselves — humans paste tokens; connect writes a scoped agent key into .plandesk/token. Full grammar: CLI Reference.
Checklist
Section titled “Checklist”| Step | Done when |
|---|---|
Turso + plandesk migrate | Domain + better-auth tables exist |
| GitHub callback | {baseURL}/api/auth/callback/github |
| Secrets | DB, PLANDESK_BETTER_AUTH_SECRET, S3/R2, optional GitHub |
| Vars | PLANDESK_BASE_URL public origin |
| SPA | web/ next to wrangler.toml |
| Deploy | wrangler deploy succeeds; /api/v1/health is 200 |
Related
Section titled “Related”- Deployment topologies — local vs self-host vs free-hosted; who migrates
- Server configuration — env/file knobs for Node/
plandesk serve - Docker (self-host) — long-running container alternative