Skip to content

Go live

Markdown

A ZeroDirs site is static files plus a small Worker. Going live is one command for the mechanical part and a short list for the parts that need your account. When this page is done you have a site on your domain, a database behind /submit/ and /admin/, and a printed list of what is still switched off.

Three things, each with a command that proves it:

Check Command You should see
wrangler is signed in to the right account pnpm exec wrangler whoami your account name and id. If it says you are not logged in: pnpm exec wrangler login opens a browser
site.url is your real domain pnpm check:config site.config.ts OK — <your site name> (https://your-domain.com). https://, no trailing slash
the domain is on Cloudflare Cloudflare dashboard → your account → the zone is listed if it is not, add it now, or deploy to *.workers.dev first with --workers-dev and come back

site.url matters more than it looks: canonicals, the sitemap, the feeds and the OG images bake it in at build time. pnpm cf:setup refuses to run while it still says demo.zerodirs.com or example.com.

  1. See what will happen. Nothing changes yet.

    Terminal
    pnpm cf:setup --dry-run

    The plan names the Worker, the route, the D1 database and the R2 bucket it is about to create or reuse, then stops with Nothing changed.:

    Plan:
    Worker name acme-directory (renamed from the template)
    Route acme.com (custom domain) (changes wrangler.jsonc)
    D1 database acme-directory (create)
    R2 bucket acme-directory-media (create if missing)
    Then migrations → build → deploy → ADMIN_SECRET / TOKEN_SECRET
    Nothing changed.
  2. Run it.

    Terminal
    pnpm cf:setup

    It asks once, then does every step in order, printing a per step and skipping what is already done, so you can run it again later. In order: it renames the Worker after your site (only while it still carries the template’s name), points wrangler.jsonc at site.url as a custom domain, creates the D1 database and writes its id into wrangler.jsonc, creates the R2 bucket, leaves the send_email binding out when your account cannot send mail yet, regenerates worker-configuration.d.ts, applies the migrations to the production database, builds, deploys, and sets ADMIN_SECRET and TOKEN_SECRET on the Worker.

  3. Store the admin password.

    If .dev.vars still held the placeholder secrets, they are replaced by generated ones, written back into .dev.vars so local and production agree, and the /admin/ password is printed once:

    Your /admin/ password (generated, also saved to .dev.vars — store it somewhere safe):
    <the value>

    Put it in your password manager now. It is also ADMIN_SECRET in .dev.vars, which is gitignored and stays on this machine.

  4. Read “What is left”.

    The command ends with the URL of the site and a list filtered to your configuration:

    Done. The site is at https://acme.com
    What is left:
    • Approved submissions live in D1; the site you just deployed was built from src/content/listings. …
    • providers.rebuild is "deploy-hook": connect the repository to Workers Builds, create a Deploy Hook …
    • Paid plans are on: pnpm cf:secrets STRIPE_SECRET_KEY STRIPE_WEBHOOK_SECRET, …
    • Open /admin/login/ with the ADMIN_SECRET from .dev.vars, and /admin/ will list anything this configuration still needs.
    Run `pnpm cf:setup` again any time; every step above skips what is already done.

    Each line is one of the pages under What is left below.

Terminal
pnpm cf:setup --workers-dev

The site goes to <worker-name>.<your-subdomain>.workers.dev and wrangler.jsonc keeps no route. When the domain is on Cloudflare, set site.url to it and run pnpm cf:setup again without the flag: it rewrites the route and redeploys.

The message says why. The three usual reasons:

Message Fix
site.url is still … Set site.url in site.config.ts to your domain, then run it again
R2 could not create the bucket R2 needs a one-time sign-up in the dashboard (R2 → Get started). Do that, run it again
the domain does not answer after a few minutes The zone is not on this account. Add the domain to Cloudflare, then pnpm cf:setup again
Command or URL You should see
The site https://<your domain>/ your home page, your name in the footer
The admin https://<your domain>/admin/login/ the login form accepts the password from step 3
What is still needed https://<your domain>/admin/ the configuration report at the top lists only what you deliberately left for later
What the Worker holds pnpm cf:secrets a list of the secrets the deployed Worker has and which ones your site.config.ts still needs

cf:setup deliberately stops at the edge of your account: it signs nobody in, creates no API tokens and touches no dashboard. These are the steps it hands to you, in the order they pay off.

Step Why Page
Build the site from the database Approved submissions live in D1, but the site you just deployed was built from src/content/listings/ Listings from D1
Deploy on every push, and after every approval A Deploy Hook lets an approval trigger a build Deploy on git push, then Publishing on approval
Send mail Receipts, approvals and your own notifications wait in the outbox until a provider can send Email
Take money Paid plans ship on and need two Stripe secrets and a webhook Plans and payments
Let submitters sign in with Google Accounts work with emailed links already; Google is optional Submitter accounts

Every secret on that list goes in with pnpm cf:secrets, which prompts for one key at a time and never prints or stores a value. Environment and secrets is the full map.

The same result without the script, for a copy where you would rather see each command:

Terminal
pnpm exec wrangler login
pnpm exec wrangler d1 create acme-directory # paste the id into wrangler.jsonc → d1_databases[0].database_id
pnpm exec wrangler r2 bucket create acme-directory-media
pnpm cf:typegen # worker-configuration.d.ts follows the bindings
pnpm db:migrate:remote
pnpm check:config
pnpm deploy # = astro build && wrangler deploy
pnpm cf:secrets ADMIN_SECRET TOKEN_SECRET

Set name and routes in wrangler.jsonc yourself first. cf:setup is idempotent; running it after a manual setup only fills what is missing.

  • Directoryscripts/
    • cloudflare-setup.ts the command itself, step by step, with --dry-run, --workers-dev and --yes
    • dev-setup.ts what pnpm dev runs first: .env and .dev.vars from their examples, local migrations
  • wrangler.jsonc name, routes, the D1 id and the R2 bucket are written here
  • worker-configuration.d.ts regenerated from the bindings; pnpm check type-errors without it
  • .dev.vars gitignored; ADMIN_SECRET and TOKEN_SECRET end up here as well as on the Worker