Skip to content

Publish the static site on Cloudflare

The owner’s instruction to follow the GCP Security Handbook deployment guide selects Git-integrated Cloudflare Pages Free for this documentation site. The private source stays in devSatym/resilience-gate-docs; the original Resilience Gate platform repository remains a read-only upstream input. This supersedes the Workers Static Assets procedure in decision 006. Decision 007 records the current choice.

The primary procedure is the handbook’s root Cloudflare deployment guide and update and redeploy guide, reviewed at ce2fcafbc8bd06adaafc47b6491f6e8771224679. Its engineering deployment design and engineering runbook explain the implementation. Their successful deployments and measurements belong to that handbook. They establish no live result for Resilience Gate documentation.

Setting Required value
Pages project resilience-gate-docs
Git source Private devSatym/resilience-gate-docs
Production branch main
Framework Astro static, with Starlight and Pagefind
Root directory site
Native build command Initially DOCS_SITE=https://resilience-gate-docs.pages.dev npm run build:cloudflare; custom-origin prefix after verified domain activation
Output directory dist
Node 22.20.0, matching .nvmrc
Base /
Expected Pages hostname https://resilience-gate-docs.pages.dev
Intended primary hostname https://resilience-gate.devsatym.xyz
Production origin input Explicit stable DOCS_SITE
Non-main preview origin Validated Cloudflare CF_PAGES_URL, selected using CF_PAGES_BRANCH

This implementation checkpoint records configuration and local verification instructions; actual later publication is recorded independently with its deployed Git identity. A configured name, API success, build success, or earlier GitHub validation result is narrower than verified hosted behavior. Record the actual project identity, Git revision, deployment ID, origin, UTC, and outcome under docs/website/audit/cloudflare-pages/. Local results belong to local-checks.json; actual setup/deployment status belongs to publication-status.json; hosted checks retain their own verification receipts. These maintenance paths are outside the public publication map.

Prior monorepo, repository-transfer, and Workers-campaign receipts remain unchanged in migration-evidence/monorepo-audit/, docs/website/audit/migration/, and docs/website/audit/cloudflare/. The valid Pages OAuth follow-up is historical authentication evidence, while the old Workers zone/Billing Read blockers describe the superseded procedure. An active Cloudflare zone and Billing Read are not prerequisites for this external-DNS Pages subdomain.

From the documentation repository root, prepare dependencies and sources. The following origin is the expected assignment for local configuration checks; it is not proof that a Pages project exists. Confirm the actual assignment before using it for remote setup:

Terminal window
cd site
npm ci
npm run source:prepare
npm run check:content
npm run check
npm run lint
npm test
export DOCS_SITE=https://resilience-gate-docs.pages.dev
npm run build:cloudflare
npm run deploy:check
npx playwright install chromium firefox
npm run test:e2e
npm run test:cloudflare

source:prepare obtains the ignored upstream checkout at the reviewed pin. build:cloudflare runs the static validation/build pipeline without uploading. The resulting publication inventory identifies documentation HEAD separately from the upstream revision and selected public-input digest. The artifact check rejects changed or stale output; rebuild from canonical sources instead of editing dist/.

Use npm run preview:cloudflare for local wrangler pages dev asset serving. test:e2e uses Astro production preview; test:cloudflare exercises Pages local routing. npm run deploy:dry-run validates a local deployment plan and makes no remote mutation. It is a project command, not a claimed Wrangler Pages deployment dry-run feature. Use SITE_TEST_PORT or AUDIT_PORT to preserve occupied local servers.

npm run audit remains the generic Astro/manual audit path. npm run audit:cloudflare captures the Pages campaign’s real rendered screenshots, axe scans, and repeated mobile Lighthouse samples under docs/website/audit/cloudflare-pages/. Website captures remain separate from the 34 reviewed platform originals and are excluded from the public gallery and static publication. Every measured result keeps its own artifact identity.

The publication stays fully static: no Astro SSR adapter, Pages Functions, application Worker, database, storage binding, analytics, or paid service is needed. Keep the native missing-page response and directly loaded nested articles; a successful homepage fallback is not a valid 404 check.

Connect only the private documentation repository

Section titled “Connect only the private documentation repository”

The retained valid OAuth observation reports user:read, account:read, pages:write, and offline_access. Confirm the intended account and current session with read-only discovery; do not infer a usable Git connection from OAuth alone. A read-only npx wrangler pages project list --json can use Wrangler’s normal saved-session refresh. If access still fails and owner sign-in is needed, the owner can run the scoped login from site/:

Terminal window
npx wrangler login --scopes account:read user:read pages:write

The owner completes the browser interaction. Keep tokens and refresh credentials out of chat, Git, logs, and public reports. This Pages procedure does not request Billing Read or Workers/zone deployment scopes to overcome the old Workers blocker.

Grant the Cloudflare Workers and Pages GitHub App access to this private documentation repository, preferably using the selected-repository grant. OAuth authorizes the Cloudflare API; the GitHub App grant independently permits Pages to fetch the repository. Keep repository visibility private. See Pages Git integration and GitHub integration.

Start with read-only ownership and source inspection:

Terminal window
npm run deploy:preflight

The preflight checks the intended account, Pages project, Git source, and expected main revision. Stop on an unrelated project, mismatched source, unknown account, unreadable state, or unexpected branch. Do not rename or replace another project to fit this procedure.

Create the project through the native Pages Git-source API, not wrangler pages project create: the latter creates a Direct Upload project that cannot later acquire Git integration. The wrapper’s initialization uses the approved GitHub repository identity, initially pauses production and preview deployments, and confirms the assigned hostname before a separate configuration step and first explicit native build. It performs no direct asset upload. Cloudflare documents project creation and the Direct Upload distinction.

Terminal window
npm run deploy:initialize

Inspect the returned project and assigned pages.dev hostname rather than deriving a stable origin by stripping a hash from a deployment URL. A different assignment is a stop condition for this configured project. Once resilience-gate-docs.pages.dev is confirmed, persist its origin across all following artifact, browser, API, and verification commands:

Terminal window
export DOCS_SITE=https://resilience-gate-docs.pages.dev
npm run deploy:configure
npm run build:cloudflare
npm run deploy:check
npm run test:e2e
npm run test:cloudflare

The configuration step sets root site, output dist, Node 22.20.0 matching .nvmrc, and the explicit reviewed origin in the native build command: DOCS_SITE=https://resilience-gate-docs.pages.dev npm run build:cloudflare. Dashboard environment settings alone are insufficient: the presence of pages_build_output_dir makes the Wrangler file authoritative, and the initial native attempt lacked DOCS_SITE. Keep Wrangler free of vars, bindings, and runtime; supply this nonsecret build input through the reviewed shell prefix instead. Wrangler configuration precedence It enables Git processing and all branch previews while keeping automatic main production paused during initial setup. Non-main previews use their own validated CF_PAGES_URL, with noindex metadata and robots controls; production must ignore an ephemeral preview URL. Build settings are described in Pages build configuration.

First native build and Pages-host verification

Section titled “First native build and Pages-host verification”

With Git source/build settings verified and automatic main production still paused, request the first explicit production build:

Terminal window
npm run deploy

This requests a native Git build of the expected main revision. Pages installs dependencies, executes the configured origin-prefixed npm run build:cloudflare, and publishes that build’s static output. For non-main builds, validated CF_PAGES_URL still supplies the actual preview origin; the shell DOCS_SITE is its stable fallback. The local wrapper must inspect the returned source revision and retain build/deployment failures as actual outcomes. It must not submit a local asset manifest as a Direct Upload substitute.

When the native deployment succeeds, verify its returned production origin:

Terminal window
npm run verify:public -- --origin https://resilience-gate-docs.pages.dev

The verifier checks strict HTTPS and served page/asset identity against the intended sealed artifact, then runs the production browser suite after its HTTP/integrity checks pass. A supported --output path can retain a separate verification receipt for each origin. A Pages build and a hosted browser pass are separate observations. Keep the actual deployment revision, local comparison artifact, and verification origin aligned.

Register the custom subdomain before changing its DNS

Section titled “Register the custom subdomain before changing its DNS”

Pages can serve an external-DNS subdomain without moving the apex zone or nameservers to Cloudflare. Register resilience-gate.devsatym.xyz with the intended Pages project before adding its CNAME. A CNAME alone does not register the Pages domain. See Pages custom domains.

Inspect exact-host DNS and current Pages domain ownership read-only. Stop on an existing unrelated record or project association. The target-only registration command is:

Terminal window
npm run deploy:domain

After the expected Pages association is confirmed, the owner adds this new record in the existing Spaceship DNS service:

Type: CNAME
Name: resilience-gate
Target: resilience-gate-docs.pages.dev

Use Spaceship’s default TTL. The target has no scheme, slash, or repository path. This new exact-host record is the DNS handoff; no nameserver migration is required. Preserve apex, MX, TXT, CAA, nameservers, and every other hostname. Do not replace an existing record, create a wildcard, or change a paid setting. If a conflict or certificate constraint appears, retain the failure and ask the owner to resolve the specific prerequisite rather than editing unrelated records.

Wait for recorded authoritative/recursive DNS observations and active Pages domain/certificate status. Confirm the hostname responds successfully using normal certificate verification:

Terminal window
dig +short CNAME resilience-gate.devsatym.xyz
curl -I https://resilience-gate.devsatym.xyz/

Do not disable certificate verification. DNS propagation or an initializing domain is not a verified HTTPS result. Keep Pages-origin metadata until the custom domain is active and a strict HTTPS request succeeds. Existing DNS/nameserver changes are outside this deployment procedure.

Promote the stable origin and enable continuous edits

Section titled “Promote the stable origin and enable continuous edits”

Only after Pages reports an active custom domain/certificate and strict custom-host HTTPS succeeds, set the production origin and rebuild metadata for the intended primary hostname:

Terminal window
export DOCS_SITE=https://resilience-gate.devsatym.xyz
npm run deploy:configure
npm run build:cloudflare
npm run deploy:check
npm run test:cloudflare
npm run deploy
npm run verify:public

The configuration step changes the approved native build command to DOCS_SITE=https://resilience-gate.devsatym.xyz npm run build:cloudflare, together with its reviewed settings and controls. It does not depend on dashboard vars being forwarded to the build. The custom-origin build regenerates canonical, social, sitemap, and search URLs. Prior pages.dev verification does not verify this promoted artifact. Default public verification uses the configured custom HTTPS origin; it must retain DNS/TLS, page/integrity, and browser outcomes separately from deployment success.

After the first intended production publication is actually verified, enable automatic main deployments; configured native branch previews remain enabled:

Terminal window
npm run deploy:continuous

The intended ongoing loop is local editing → meaningful checks → work-branch push → Pages preview review → merge/push main → native production build → verify the new deployment. Inspect git status before pulling or creating a branch, preserve unfinished work, and stage reviewed source files deliberately; generated audits and captures are not routine publication inputs. Local saves alone do not publish. Include site code/configuration, canonical teaching pages, curated engineering reports, upstream pin, and documentation workflows in build watch paths; exclude private generated audit/history/capture files. Keep PR comments disabled when configuring the source controls.

GitHub Actions remains a separate read-only validation workflow with no Cloudflare publishing secret/job. Native Pages Git builds do not automatically wait for its browser checks. Review passing checks and the branch preview before merging. After continuous deployment is enabled, relevant main pushes publish through Pages rather than through a GitHub deployment job. Build watch paths

The current Pages Free limits are 500 builds/month, one concurrent account-wide build, a 20-minute timeout, 20,000 static files, and 25 MiB per file. Production and preview builds share the monthly allowance. Static serving needs no Functions; account quotas and current terms still apply. GitHub Actions has a separate private-repository allowance. No purchase, upgrade, or unlimited-build promise is part of this setup. Pages limits

Preview origins are public by default and Cloudflare supplies a noindex header. The site also uses preview metadata/robots controls. Noindex prevents indexing; it does not authenticate visitors. Private Git source does not make production or previews private. A specific preview must be verified from its matching non-main source revision and exact returned origin, not a stale production artifact:

Terminal window
read -r -p 'Exact HTTPS project preview origin: ' rg_docs_preview_origin
export CF_PAGES=1
export CF_PAGES_BRANCH=$(git branch --show-current)
export CF_PAGES_URL="$rg_docs_preview_origin"
npm run build:cloudflare
npm run deploy:check
npm run verify:public -- --origin "$rg_docs_preview_origin"
unset CF_PAGES CF_PAGES_BRANCH CF_PAGES_URL

The origin validator rejects unrelated hosts and a production hostname used as a preview. Keep each preview’s source, deployment, artifact, and verification identities together. Rebuild production after clearing preview variables; its stable DOCS_SITE must still be correct. Preview deployments

Observation Required response
Missing Pages API access or GitHub App grant Owner resolves the specific grant; retain blocked setup, without changing billing or visibility
API error 8000012: repository inaccessible Confirm GitHub still exposes the private repo, then owner opens the Cloudflare Workers and Pages GitHub App installation, selects resilience-gate-docs under Only select repositories, and saves the grant; retry read-only preflight before paused initialization. Repeated Cloudflare login or Workers/billing scopes do not supply that GitHub permission
Existing unrelated Pages project/domain Stop; do not rename, detach, or replace it
Initial creation or build fails Preserve response/revision and logs; do not relabel it as publication
Native build succeeds but hosted checks fail Record deployment and verification separately; inspect the intended revision, output, routing, and origin
Custom CNAME absent or domain/certificate pending Keep custom-host publication unverified; owner completes only the new exact-host DNS record
Quota or timeout reached Reduce unnecessary builds or diagnose build work; do not enable a paid plan automatically

Completion requires actual project/source configuration, native deployment identity, strict hosted verification, custom-domain DNS/certificate observations, and a separately observed preview/continuous path. Record what ran under docs/website/audit/cloudflare-pages/; leave missing phases BLOCKED, NOT RUN, or UNVERIFIED with their reasons. No handbook result or earlier local pass fills a missing receipt.

For a production rollback, select a previously successful production deployment and verify the restored revision, routes, search, originals, and metadata. A preview is not a production rollback target. Rollback changes the deployed version rather than main; the next successful production build can replace it. For a lasting source correction, use a reviewed revert PR instead of resetting or force-pushing main. No rollback or DNS restoration is claimed here. Pages rollbacks

Maintained by Satyam Agnihotri · DevOps & Cloud Engineer