Skip to Content
Living documentation — last reviewed 2026-05-28
RunbooksDocs site deploy (Cloudflare Pages + Access)

Docs site deploy (Cloudflare Pages + Access)

The docs site at apps/docs/ (Nextra v4) deploys to Cloudflare Pages and is gated behind Cloudflare Access. This runbook covers the one-time setup, the automated deploy pipeline, and how to manage who can read the docs.

What ships where

SurfaceURLAuth
Local devhttp://localhost:3030none
Productionhttps://fitkit-docs.pages.dev (or custom domain)Cloudflare Access
Source/docs/ in this repo (canonical markdown)repo permissions

Pipeline

.github/workflows/deploy-docs.yml triggers on main pushes that touch docs/**, apps/docs/**, or the workflow itself.

push to main with docs change build apps/docs (pnpm install + pnpm build → out/) cloudflare/wrangler-action@v3 → `wrangler pages deploy out --project-name=fitkit-docs --branch=main` Cloudflare Pages serves out/ from fitkit-docs.pages.dev Cloudflare Access gates the request (SSO / email policy)

Builds run on every matching push. Concurrency group docs-deploy prevents overlapping runs.

One-time setup

1. Create the Cloudflare Pages project

In the Cloudflare dashboard → Workers & PagesCreatePagesDirect Upload → name it fitkit-docs. Direct Upload (not Git integration) is correct here — the GitHub workflow does the building, Cloudflare just hosts the artifact.

You can leave the production branch blank; the workflow passes --branch=main explicitly.

2. Mint a Cloudflare API token

Cloudflare dashboard → My ProfileAPI TokensCreate TokenCustom token.

Permissions needed:

  • AccountCloudflare PagesEdit

Scope: limit to the specific account that owns fitkit-docs. Copy the token immediately; you won’t see it again.

3. Find your account id

Cloudflare dashboard → any zone or the Workers & Pages page → right sidebar → Account ID. Copy it.

4. Add the two secrets to GitHub

Repo → SettingsSecrets and variablesActionsNew repository secret:

NameValue
CLOUDFLARE_API_TOKENToken from step 2
CLOUDFLARE_ACCOUNT_IDAccount id from step 3

5. Configure Cloudflare Access

Cloudflare Zero Trust dashboard → AccessApplicationsAdd an applicationSelf-hosted.

Settings:

  • Application name: FitKit docs
  • Application domain: fitkit-docs.pages.dev (or your custom domain) — path /*
  • Session duration: whatever fits (24h is reasonable)

Then add a policy:

ActionAllow
IncludeEmails ending in @desmotech.com (or specific email list)
Optional requireGoogle / Microsoft / GitHub SSO

Multiple policies can stack — e.g., a permissive “Allow team emails” and a more restrictive “Require MFA for these paths”. Default is single-policy.

6. (Optional) Custom domain

If you want docs.fitkit.fit instead of the .pages.dev URL:

  1. Cloudflare Pages project → Custom domainsSet up a custom domaindocs.fitkit.fit.
  2. Add the CNAME Cloudflare provides at your DNS provider (or directly in Cloudflare if the zone is there).
  3. Update the Access application domain to match.
  4. (No workflow change needed — wrangler pages deploy doesn’t care about the public hostname.)

Day-to-day

Triggering a redeploy

Just push to main with a change under docs/** or apps/docs/**. Or run the workflow manually: ActionsDeploy docs to Cloudflare PagesRun workflow.

Cloudflare retains the last several deployments — you can roll back from the Pages project dashboard if a deploy goes bad.

Granting access

Cloudflare Zero Trust → AccessApplicationsFitKit docsPolicies → edit. Add an email, remove one, or add a whole identity provider group. No deploy needed; Access policies apply immediately.

Revoking access

Same place. Removing the policy locks the user out within seconds.

Adding a new doc

Edit any file under /docs/ (canonical source). Push to main. The deploy workflow runs automatically. Don’t edit apps/docs/content/ — it’s a regenerated mirror.

Why this setup, not GitHub Pages

  • Auth. GitHub Pages on a regular plan is public-only. Cloudflare Access lets us gate by SSO / email without a GitHub Enterprise Cloud subscription.
  • Custom domain. Pages supports custom domains under the same Access policy; GitHub Pages would require the repo to be public anyway.
  • Faster invalidation. Cloudflare’s CDN updates within ~30s of a deploy. GitHub Pages can lag.

Failure modes

SymptomCauseFix
Workflow fails at “Deploy to Cloudflare Pages” with auth errorCLOUDFLARE_API_TOKEN missing / expired / wrong scopeRe-mint per step 2; resave secret.
Workflow succeeds but URL still shows old contentCloudflare CDN cacheCloudflare Pages bypasses cache automatically per deploy. If stuck, Purge Everything on the project’s zone.
Pages live but every request hits a Cloudflare Access login loopDomain not added to Access application, or policy excludes youZero Trust → Access → Applications → edit domain / policy.
Build fails at pnpm installLockfile drift after deps addedThe workflow runs pnpm install --frozen-lockfile=false so this is rare — check the failing log.
Nextra build hangs on Pagefind indexingMemory cap on the GitHub Actions runnerDrop search: { codeblocks: true } to search: true in apps/docs/next.config.mjs temporarily.