Deployment
Deploy one Worker, complete first-run setup, and activate Cloudflare mail services safely.
Simple Inbox deploys as simple-inbox-cf. The root wrangler.jsonc declares its D1 database
simple-inbox-cf-db, private R2 bucket simple-inbox-cf-raw, Email Sending and rate-limit bindings,
and daily retention cron. Wrangler provisions D1/R2 when needed; you do not copy resource IDs into
the repository.
Deployment never changes DNS, custom domains, or Email Routing, and never reads or mutates a legacy Inbox installation.
Prerequisites
- A Cloudflare account with Workers, D1, R2, and Email Routing.
- Email Routing enabled on the intended new mail zone and at least one owner-controlled destination
verified before deployment; Cloudflare requires both before attaching the
EMAILbinding. - Workers Paid and an onboarded Email Sending domain before testing full compose/reply delivery to arbitrary recipients.
- Wrangler authenticated to the intended account.
- The repository's pinned Node, pnpm, and Vite+ versions.
- Two different secret values of at least 32 random bytes.
- An owner-controlled mail domain/subdomain and allowlisted test destination.
- An approved raw/application retention policy.
Verify locally
vp install --frozen-lockfile
vp run check:generated
vp run check
vp run test:boundaries
vp test
vp run build
vp run test:integration
vp exec playwright install chromium
vp run test:e2e
vp exec wrangler whoamiThe test harness uses local D1/R2 and simulated Email Sending. It sends no real mail.
The upload runs Wrangler non-interactively to keep provisioned IDs out of source. If whoami lists
multiple accounts, set CLOUDFLARE_ACCOUNT_ID for the current shell or CI project only; never add it
to the repository.
Deploy manually
For the first manual deployment, after confirming Wrangler's account, run:
vp run deploy:firstThis command is immediately remote and state-changing. It builds and deploys the fail-closed Worker
so Wrangler can provision D1/R2, then applies the checked-in migrations. Once migration completes,
the app is ready for /setup without another upload.
For later upgrades, run:
vp run deployThe upgrade command:
- builds the TanStack Start Worker;
- applies checked-in D1 migrations remotely;
- deploys the generated
apps/web/dist/server/wrangler.jsonwithCI=1, preventing Wrangler from writing an auto-provisioned D1 ID back into tracked source configuration.
Deploy to Cloudflare provisions resources before invoking the regular deploy script, so its
one-click flow also follows the migration-before-upload sequence. There is no separate provision,
bootstrap, dry-run, or multi-Worker deploy script. Do not deploy a stale generated config or
generate migrations during deployment.
Configure secrets
The Deploy to Cloudflare flow prompts for both values. For a manual deployment, add them through the Worker's Cloudflare Dashboard settings or Wrangler's interactive prompts:
vp exec wrangler secret put AUTH_TOKEN_PEPPER --config wrangler.jsonc
vp exec wrangler secret put SETUP_TOKEN --config wrangler.jsoncAUTH_TOKEN_PEPPER protects magic-link, session, and API-token digests. Rotating it invalidates
those outstanding credentials. SETUP_TOKEN authorizes installation setup and must be independently
generated. Never pass either plaintext value in command arguments or store it in the repository.
Choose the origin and finish setup
Setup stores the origin from its verified same-origin HTTPS request. Before opening /setup, either
keep the generated workers.dev origin or manually attach the intended custom domain. Do not finish
setup on one origin and silently move to another later.
At /setup, enter the setup token and installation values. Synthetic examples are:
- owner:
owner@example.test - mail domain:
mail.example.test - inbox:
inbox@mail.example.test - raw retention: 30 days
- application-record retention: 90 days
- batch size: 100
Raw retention must be 1–3,650 days, application retention must be at least as long and no more than 3,650 days, and the batch must be 1–100.
One D1 transaction creates the owner, primary mailbox, sole owner membership, canonical app origin, mail domain, and retention settings. Exact replay is idempotent; conflicting or partial state fails closed. The setup token is never stored, returned, or logged.
Before setup completes, inbound mail is rejected, the scheduled job is idle, and protected API routes return unavailable.
Dashboard-only mail and lifecycle setup
These owner actions are not part of deployment:
- Onboard the Email Sending domain and verify SPF/DKIM.
- Verify only owner-controlled test destinations; keep arbitrary sending disabled until reviewed.
- Confirm the Worker's
EMAILbinding can deliver a magic link and synthetic outbound mail. - Keep
simple-inbox-cf-rawprivate with nor2.devURL/custom domain. - Add an R2 lifecycle rule at approved raw retention plus a short grace, such as two days.
- Only after setup and outbound validation, add a test-domain Email Routing rule/catch-all targeting
simple-inbox-cf'semail()handler. - Do not modify an existing legacy mail rule as part of this process.
Acceptance
Check public pages and metadata, then perform owner-only live validation with uniquely identifiable synthetic content:
- request, consume, and attempt to reuse a magic link;
- capture one inbound message in D1 and private R2;
- verify forwarding and a reply round trip;
- round-trip a small non-sensitive attachment and authorize its download;
- confirm repeated outbound idempotency keys do not duplicate delivery;
- confirm public
/internal/*probes return 404; - correlate safe request IDs without recording addresses, bodies, tokens, or R2 keys;
- confirm no legacy resource or route changed.
There is no automated live-smoke command. Real mail and route changes require the owner's explicit approval.
Future Deploy to Cloudflare button
Once the source repository is public:
Deploy Simple Inbox to Cloudflare
Cloudflare can clone the repository, prompt for described secrets, run the custom deploy command, and provision supported resources. Private repositories do not work for other deploy-button users, so this link is future guidance until the repository is public. See Cloudflare's deploy-button documentation.
Upgrades and rollback
For upgrades, back up D1 when the migration warrants it, run the full local suite, and run
vp run deploy. Pending migrations are applied before the new code is uploaded; setup and secrets
are not recreated.
Preserve the Worker version and change record. A Worker rollback restores code only: it does not undo D1 migrations or restore deleted D1/R2 data. Custom-domain and Email Routing rollback are manual. Keep replacement storage intact for investigation, and never expect captured mail to merge automatically into another store.