Skip to content

Go live

Deployment reference

Every owner input in detail, the checks a deploy runs, hosting on workers.dev and an independent heartbeat.

On this page

Lamp uses distinct public page and operator application hosts. Each has its own home page: the page host's / is the company's public status page, and the app host's / is the Lamp landing page beside sign-in and the operator app. Its deployment commands provision a real D1 database, R2 bucket and Queue by environment name, apply migrations, initialize the first operator and page settings, build the Worker and publish the emitted artifact. rer deploy runs all of these; pnpm run setup:cloudflare runs the provisioning alone. (pnpm run setup is the local first-owner setup.)

Owner inputs

Supply CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_API_TOKEN for the intended account. The token needs Worker deployment, D1, R2, Queues and custom-hostname access, including Zone Workers Routes read/write permission for both hosts’ zones. Account Worker access alone can upload the artifact but cannot attach its hosts. Configure LAMP_PAGE_HOST, LAMP_APP_HOST, LAMP_PAGE_NAME, LAMP_PAGE_TAGLINE, LAMP_PAGE_TIMEZONE, LAMP_ACCENT_COLOR, SETUP_OPERATOR_EMAIL, MAIL_FROM_ADDRESS, MAIL_DKIM_SELECTOR, MAIL_PROVIDER_API_KEY, SUBSCRIBER_TOKEN_SECRET and WEBHOOK_SIGNING_SECRET. The two token secrets must each contain at least 32 characters. Keep their original values when restoring so existing subscriber tokens and webhook signatures remain valid. Store owner inputs outside committed source.

Optionally set OWNER_DISPLAY_NAME to the first owner's name (1–120 characters). It is used only when setup creates the first operator; existing owners keep their name and access. Without it, the native command retains its Setup operator name.

MAIL_PROVIDER selects resend (default, preserving existing deployments) or sendgrid. Both use MAIL_PROVIDER_API_KEY; map an existing provider-specific credential into that environment variable without writing it into source. Likewise map the verified sender address into MAIL_FROM_ADDRESS. The sender domain must publish SPF, DMARC and a DKIM key at the chosen selector. Setup checks those records before provisioning. It does not prove DKIM's header coverage or recipient delivery: verify those against a received message.

For SendGrid set SENDGRID_WEBHOOK_PUBLIC_KEY to its base64 P-256 public key and configure the signed Event Webhook URL as https://<LAMP_PAGE_HOST>/api/intake/mail-events, with delivered, bounce, dropped and spamreport events enabled. For Resend, set RESEND_WEBHOOK_SECRET and use the same URL. Without the selected provider's verification key this endpoint rejects callbacks; API acceptance alone does not mark recipient delivery.

SendGrid requests explicitly disable click, open, subscription and analytics tracking. Verify the received message has no added tracking and that DKIM's h= list covers List-Unsubscribe and List-Unsubscribe-Post before claiming one-click mailbox-provider support. A provider setting or received message that fails these checks is a release blocker, not a reason to claim the behavior locally.

Deployment and checks

Shell
pnpm install --frozen-lockfile
pnpm exec playwright install chromium
rer deploy --dry-run --environment staging
rer deploy --environment production

Dry run compiles and validates generated configuration without changing Cloudflare. Real deploy first runs setup and verification. Setup does not create a placeholder Worker or publish secrets separately. Deploy writes a private temporary secrets file, publishes the real Worker with it, removes that file even after failure, then checks the application host's health with a bounded request. It checks real D1/R2/Queue reachability, not mail delivery. The public host must also be exercised with actual published content, subscription and signed provider receipts.

The GitHub workflow builds and retains lamp-worker-<commit> without deployment credentials. node scripts/build-delivery-artifact.mjs packages a completed pnpm build into delivery-artifact/lamp-worker-artifact.json: Worker modules and static assets only, using the delivery service's ArtifactBundle schema. It does not carry resource authority, secrets, migration instructions or trustworthy source identity. The independent delivery service validates the run and retained bytes, then applies the approved resource plan. Its authority must live outside the editable application build job. Artifact creation alone does not deploy Lamp. Direct owner deployment remains available with rer deploy.

Native workers.dev deployment

Custom domains remain the default. To use the account's existing Workers subdomain without custom DNS, set LAMP_HOSTING=workers-dev. Set LAMP_RESOURCE_PREFIX to an explicit lowercase resource namespace (letters, digits and hyphens, at most 47 characters). If omitted, it is lamp-<environment>; the environment defaults to production.

The app host is exactly <prefix>.<subdomain>.workers.dev and the page host exactly <prefix>-page.<subdomain>.workers.dev, with your account's Workers subdomain as <subdomain>; any other names are refused. For a prefix my-status and the Workers subdomain my-account, set:

Shell
export LAMP_HOSTING=workers-dev
export LAMP_RESOURCE_PREFIX=my-status
export LAMP_APP_HOST=my-status.my-account.workers.dev
export LAMP_PAGE_HOST=my-status-page.my-account.workers.dev
rer deploy

Configure the remaining inputs from the README deployment table before running these commands. Find the account subdomain in Cloudflare Workers settings; setup verifies it against the authenticated account before creating resources. It never changes account-level subdomain settings. The app Worker is named exactly the prefix; the public Worker adds -page. D1 adds -db, R2 adds -files, and the queue adds -jobs. The generated config records the supplied account ID. Deployment records preserve actual resource names for archive and sign-in commands.

Both Workers serve the same compiled source and retain the configured host checks: operator paths on the public hostname return 404, and operator APIs on the app hostname require a session. The app Worker owns the scheduled jobs, queue consumer and snapshot Durable Object. The public Worker uses that same object and storage without a second scheduler or consumer. The command deploys the app Worker first, then the public Worker. Keep the prefix reserved for this installation, and remove both Workers when retiring it.

This mode is supported by native rer deploy. The independent delivery artifact contract describes one Worker; it does not package this two-Worker topology.

Independent external heartbeat

Set LAMP_HEARTBEAT_URL to the public HTTPS ping URL of the owner's chosen external heartbeat service. It is off when omitted. Keep this capability URL secret. LAMP_HEARTBEAT_INTERVAL_MINUTES defaults to 5. Configure the service's expected interval and grace period to match; the service sends the alarm when pings stop. Choose the receiving mailbox and phone on infrastructure independent of this hosting provider.

The minute cron sends an empty GET only on the heartbeat interval grid, after scheduled work completes and /health verifies D1, R2 and Queue. Failed dependencies and the hosting-move EFFECTS_PAUSED=1 hold stop pings. No subscriber, incident, page, visitor or owner data travels. A successful ping establishes the service acknowledged that ping; it does not prove human receipt. This watch does not provide standby hosting.

This page is drawn from OPERATIONS.md in the repository. Edit it on GitHub.