Runbook — serve the vault at vault.pragalva.me (Cloudflare Pages + Access)

This is the Phase B the DNS runbook (cloudflare-migration-runbook.md) deferred. Phase A (move pragalva.me DNS to Cloudflare) is already done: dig NS pragalva.me returns aragorn.ns.cloudflare.com / stevie.ns.cloudflare.com.

Decision (recorded 2026-06-27): host the Quartz vault on Cloudflare Pages, delivered by Git-connect (Cloudflare builds on every push to GitHub), with Cloudflare Access as the login gate. Pages was chosen over self-hosting on devata because the cluster has no public ingress / TLS / GitOps backbone yet. When that backbone exists, this can migrate to a self-hosted origin behind a Cloudflare Tunnel and the Access app + DNS stay unchanged (only the origin moves).

Repo: PragalvaXFREZ/homelab-vault, production branch master.

Build facts (verified locally 2026-06-27)

  • Build command: npx quartz plugin install && npx quartz build
    • npx quartz build ALONE FAILS in CI: .quartz/ (where plugins install) is gitignored and the config pulls a remote plugin (github:quartz-community/created-modified-date), so plugins must be installed at build time. The Dockerfile does the same two-step. Cloudflare’s build image has git, so the github: plugin installs fine.
  • Build output directory: public
  • Node version: .node-version pins v22.16.0; Cloudflare Pages reads it automatically. If a build ever picks the wrong Node, set env var NODE_VERSION=22.16.0 to force it.
  • Verified: clean build emits public/index.html (14 notes published, private/ excluded).

B1 — create the Pages project (Git-connect)

  • Cloudflare dashboard -> Workers & Pages -> Create -> Pages -> Connect to Git.
  • Authorize the Cloudflare GitHub app, select repo PragalvaXFREZ/homelab-vault.
  • Production branch: master.
  • Build settings:
    • Framework preset: None
    • Build command: npx quartz plugin install && npx quartz build
    • Build output directory: public
    • Root directory: / (default)
  • (Optional) Environment variables: NODE_VERSION=22.16.0.
  • Save and Deploy. Watch the build log; first build takes a few minutes (plugin install + build).

Verify B1: the project’s https://<project>.pages.dev URL serves the vault homepage.

B2 — custom domain vault.pragalva.me

  • In the Pages project -> Custom domains -> Set up a custom domain -> vault.pragalva.me.
  • Because Cloudflare is authoritative for pragalva.me, it auto-creates the proxied CNAME vault -> <project>.pages.dev and issues a managed TLS cert. No manual DNS record needed.

Verify B2:

  • dig +short vault.pragalva.me resolves (Cloudflare-proxied IPs).
  • https://vault.pragalva.me serves the vault with a valid cert.

B3 — Cloudflare Access (the login gate)

First-time Zero Trust setup: Cloudflare dashboard -> Zero Trust. Pick a team name (<team>.cloudflareaccess.com). The free plan covers up to 50 users; onboarding may ask for a card even though it stays free at this scale.

  1. Zero Trust -> Settings -> Authentication -> add a login method. Simplest is One-time PIN (email OTP, no IdP setup). Google login also works well since the allowed account is a Gmail.
  2. Zero Trust -> Access -> Applications -> Add an application -> Self-hosted.
    • Name: Homelab Vault
    • Session duration: 1 week (personal site, low risk).
    • Public hostname: vault.pragalva.me (leave path blank to gate the whole site).
  3. Add a policy:
    • Action: Allow
    • Include: Emails -> dhirajs6342@gmail.com (add more later to share).
  4. Save.

Verify B3: open https://vault.pragalva.me in a private window -> redirected to the Cloudflare Access login -> after email OTP / Google, the vault loads. Without auth, no access.

Update flow after this is set up

Edit notes under content/, commit, push to master. Cloudflare rebuilds and redeploys automatically. Nothing to run by hand.

Rollback

  • Remove the gate: Zero Trust -> Access -> Applications -> delete the Homelab Vault app (the site becomes public but still served).
  • Take the site down: Pages project -> Custom domains -> remove vault.pragalva.me, or delete the Pages project. The vault CNAME disappears with the custom domain.
  • None of this touches the apex blog or the zone’s other records.

Watch-item (not blocking the vault)

The apex A pragalva.me currently resolves to Cloudflare proxy IPs (104.21.70.28 / 172.67.218.205), i.e. it is proxied (orange cloud), not the DNS-only Vercel IP the DNS runbook specified. The blog still returns HTTP 200 through the proxy, so it is working, but the runbook’s caution about Vercel + Cloudflare proxy (SSL / redirect-loop edge cases) stands. If the blog ever misbehaves, set the apex record to DNS only (grey cloud) in the Cloudflare DNS panel.