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-storage, Email Sending and rate-limit bindings;
no retention cron is enabled. 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.
- R2 object expiration disabled for retained mail and attachments.
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
Mail and attachments are retained indefinitely. Setup does not ask for expiration windows.
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-storageprivate with nor2.devURL/custom domain. - Disable all R2 lifecycle rules, including the default incomplete-multipart-upload rule. When upgrading, also clear the old bucket’s rules; deployment cannot override bucket lifecycle.
- 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.
Deploy to Cloudflare button
Deploy the public source repository:
Deploy Simple Inbox to Cloudflare
Cloudflare can clone the repository, prompt for described secrets, run the custom deploy command, and provision supported resources. The source repository must remain public for this flow. 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.
Attachment upload setup
The deployment declares a private simple-inbox-cf-storage bucket with the STORAGE
Worker binding. Both uploads and downloads stream through the Worker. No R2 S3 credentials,
additional secrets, bucket CORS setup, or public bucket access are required. Local development
uses the same API with local R2.
Authorize the new bucket, the linked-attachment D1 migration, and the Worker deployment before running the upgrade. Wrangler needs Worker deployment, D1 write, and R2 provisioning permissions on the intended account. Existing authentication secrets and Email Routing remain unchanged. See the repository operations runbook for the upgrade procedure.
Recipients use permanent application download links. Anyone with a link can access its file, including recipients of forwarded emails. Existing R2 lifecycle rules must be removed separately by the owner; deployment cannot override them. Live email tests also require separate owner authorization.