Every Cloudflare product is well-documented in isolation. The interesting bugs are always at the seams between two products — the edge injecting scripts into HTML that already has a CSP, the WAF inspecting requests for media served from R2, Vite substituting variables at build time that don't exist yet on Pages. These three patterns are from running nadiapoe.co.uk on Astro 6 + Pages, with R2 hosting the artwork media.

1. CSP nonces via middleware, not build-time hashes

The textbook way to do a strict CSP on a static site is build-time hashing: scan every inline <script>, hash it, list the hashes in the CSP header. Cloudflare even has a build hook to do it for you.

For an art site, Bot Fight Mode is non-negotiable — automated scrapers harvesting painting images are a real concern, and Cloudflare's challenge platform is the cheapest layer of protection available. But it breaks the moment you enable it. Cloudflare's edge injects the challenge widget at request time with a rotating token. The hash changes per request. Your CSP rejects it. Half your visitors get a broken challenge widget because the static hash you baked in this morning no longer matches.

The fix is a per-request nonce. Astro 6's middleware runs as a Worker; Workers have HTMLRewriter. From client/src/middleware.ts: