Skip to content

Deploy to your Cloudflare account

Two ways to put Tinbox on your own Cloudflare account — the one-click button or the local tinbox CLI — plus the dashboard and command steps for everything the deploy can't finish for you.

Tinbox runs entirely on your Cloudflare account. Nothing transits a Tinbox relay — your mail, keys, and subscriber data never leave infrastructure you own.

Every path below deploys the same one bundled worker (createWorker()), which handles fetch (the API + inbox UI), email (inbound via Email Routing), queue, and scheduled. It needs a small, fixed set of resources on your account — a D1 database (mail + audiences), an R2 bucket (raw .eml + attachments), a KV namespace (routing cache), and two Queues (newsletter fan-out + inbound projection, each with a dead-letter queue). Resources are named tinbox-<org>-*, so several tenants can share one Cloudflare account.

Pick a path

PathWhen to useAuth
One-click buttonNo terminal; fastest first deployCloudflare dashboard sign-in
tinbox CLIOne command, full control, scriptablewrangler login or an API token

Using a coding agent?

Give it the canonical agent runbook, your domain, and permission to stop for HUMAN STEPs. It runs the same preflight and CLI path below, then hands you to the deployed web app to claim the owner account. The runbook is the source of truth for agent-assisted setup.

What each path automates vs. leaves to you

StepOne-click buttontinbox CLI
Cloudflare auth✓ dashboard sign-inwrangler login / token
Provision D1 / R2 / KV / Queues✓ auto-provisioned✓ tinbox setup
Migrations (baseline schema)✓ via deploy script✓ tinbox setup
Internal secrets (BETTER_AUTH_SECRET, ASSET_SIGNING_KEY)prompted in deploy form✓ auto-generated
External keys (AI, GitHub OAuth)prompted in deploy formprompted
Deploy the worker✓✓ --deploy
Custom domainmanual (deploys to workers.dev)route in config
Inbound Email Routingfinish in-app✓ with token (else guided in-app)
Sending DNS (SPF/DKIM/DMARC)manual✓ attempted with token (else one guided dashboard step)
"Continue with Tinbox" SSOin-app✓ domain proof

The CLI path is the only path that can automate Cloudflare's mail-plane APIs. With a scoped API token, tinbox setup enables Email Routing, points the catch-all at your live worker, and onboards Email Sending before you open the app. The Finish the setup section is the clear fallback for work a token cannot do or verify.

Path 1 — One-click (Deploy to Cloudflare)

Best when you want an inbox live without touching a terminal. The button clones a small project repo into your GitHub, provisions the resources, and deploys — all from the Cloudflare dashboard.

  1. From a button-ready repo (see examples/cloudflare-button), click Deploy to Cloudflare.
  2. Sign in with your Cloudflare account, review the setup page (Worker name, resource names), and fill in any prompted secrets.
  3. Cloudflare auto-provisions D1/R2/KV/Queues, builds with Workers Builds (npm install → npm run deploy), and deploys. Every later push to your new repo redeploys.

The button deploys to a *.workers.dev host and can't touch your DNS, so after it finishes, attach a custom domain and turn on mail — see Finish the setup. The in-app onboarding walks you through the same steps.

Path 2 — The tinbox CLI

Best when you have a terminal and want one idempotent command to do the whole provision. Check the requirements, scaffold, then set up:

# Before creating a project — Node 20+, package manager, zone and plan:
npx tinbox doctor --preflight yourdomain.com

# Authenticate once — wrangler login, or an API token for zero-click mail setup:
wrangler login
npx tinbox init yourdomain.com
cd tinbox-yourdomain-com
tinbox setup --deploy
tinbox doctor            # read-only health report: what's set up, what's left

tinbox setup is idempotent — run it again any time; it only does what's still missing. With a CLOUDFLARE_API_TOKEN it turns on Email Routing, attaches the catch-all to your worker, and onboards Email Sending. Without one, the running app shows only the remaining guided Cloudflare step. It prompts for external keys (ANTHROPIC_API_KEY, GitHub OAuth) it can't generate.

Finish the setup

The CLI automatically completes the mail-plane steps below when CLOUDFLARE_API_TOKEN has the documented Email Routing and Email Sending scopes. Use these instructions for the one-click path, a no-token CLI deploy, or an API failure. Settings → Domains always shows the current live state and the next remaining action.

Attach a custom domain

Needed for a real address and for SSO. The domain's zone must be on this account.

Workers & Pages → your worker → Settings → Domains & Routes → Add → Custom Domain → tinbox.<your-domain>.

Add the route to wrangler.jsonc, then redeploy:

"routes": [{ "pattern": "tinbox.&#x3C;your-domain>", "custom_domain": true }]
pnpm wrangler deploy

Turn on inbound mail (Email Routing)

Inbound mail reaches the worker's email() handler via a catch-all rule.

Your domain → Email → Email Routing → Enable, then add a catch-all rule → action Send to a Worker → select your worker.

With a CLOUDFLARE_API_TOKEN set, this enables routing and points the catch-all at the worker for you (wrangler has no Email Routing command, so the CLI uses Cloudflare's API):

pnpm tinbox setup

Addresses still have to exist as inbox addresses in the app for mail to be accepted.

Verify your sending domain

Sending needs SPF, DKIM, and DMARC records on your domain.

Add the SPF, DKIM, and DMARC records at your DNS provider (or your domain's DNS tab if it's on Cloudflare). Until the domain is verified you can only send to verified destinations.

Print the exact records — and publish them automatically when your DNS is on Cloudflare and a token is set:

pnpm tinbox setup

Set secrets

Worker → Settings → Variables and Secrets → add BETTER_AUTH_SECRET (required for sign-in), ANTHROPIC_API_KEY (or OPENAI_API_KEY), ASSET_SIGNING_KEY, and GitHub OAuth keys as needed.

tinbox setup generates and pushes the internal ones; set the rest by hand (value read from stdin):

wrangler secret put BETTER_AUTH_SECRET
wrangler secret put ANTHROPIC_API_KEY

Enable sign-in for the default auth.mode: "tinbox"

This step is required before anyone can sign in when you keep the default auth mode. It is optional only when you explicitly switch tinbox.config.ts to auth.mode: "local" and redeploy.

Settings → Sign-in → Enable, add one DNS TXT record to prove the domain, then Re-check — no redeploy.

Run the same domain proof and write the SSO credentials as worker secrets:

pnpm tinbox setup

Verify

tinbox doctor      # what's provisioned, migrated, and wired
tinbox whoami      # confirms the token reaches your account + inboxes

When those look right, send yourself a test message and watch it land in the inbox UI.