~/notes / deploy-cloudflare-pages

#howto · #dns #security · 2026-10-15

Deploying a static portfolio to Cloudflare Pages

How this site went from a GitHub repo to doof.quest on Cloudflare Pages: no build step, security headers in the repo, and clearing an apex domain that an old tunnel and Access app were still holding.

$ cat goal

  • Serve this portfolio at doof.quest from Cloudflare Pages, so it stays up even when the homelab doesn't.
  • Keep the deploy boring: push to main and the site updates.
  • Leave SSH remote access and the internal services exactly as they were.

$ cat design

The site is plain HTML, CSS and JS. A small Node script fills the pages from a data file, and I commit its output in site/. Pages pulls the repo from GitHub and serves that folder as is. Cloudflare doesn't run a build step, so what I test locally is exactly what goes live.

The domain already lived on Cloudflare, so attaching it was one CNAME at the root pointing to the project's pages.dev address. Cloudflare flattens it into real IPs, which is what makes a CNAME legal at the apex.

$ cat decisions

  • Pages, not Workers. The dashboard now steers new projects to Workers, which wants a wrangler config and an API token. For a folder of static files, Pages needs neither. It sits behind a small "Continue to Pages" link at the bottom of the create screen.
  • No build command. Framework preset None, build command empty, output directory site. Only that folder is published. The build script and source data stay in the repo but never get served.
  • Security headers in a _headers file. CSP, HSTS, framing and referrer rules live in the repo next to the pages, so they're versioned with everything else.

$ cat gotchas

  • The root was already taken. An old Access application put a login in front of doof.quest, and a leftover tunnel route held the root with a CNAME. I deleted the Access app and the route, kept the SSH app and route, and checked that SSH still worked from outside before going further.
  • Deleting a tunnel route doesn't always delete its DNS record. Check the DNS page afterwards, or Pages can't claim the name.
  • Tunnels moved. They're under Networking now, not Zero Trust.
  • It worked everywhere except my house. A wildcard rule in Pi-hole still sent the root to my reverse proxy. That one got its own postmortem.

$ cat verify

dig +short doof.quest               # Cloudflare IPs, at home too
dig +short doof.quest @1.1.1.1      # same answer
curl -sI https://doof.quest | grep -i strict-transport

securityheaders.com gives it an A+.

$ cat lessons

  • Clear the name before you claim it. Access apps, tunnel routes and DNS records can all hold the apex, and each one lives on a different page.
  • Test from two networks. From outside it looked finished. Only the home network showed the Pi-hole problem.
lab up — · 8 notes ·