Cloudflare Pages Deployment Notes
The whole chain from a GitHub push to edge nodes. How we wire up _headers, _redirects, caching policy, and where the SSR Worker boundary sits.
The site runs at the edge, not in some data center.
Traps we didn’t fall into (because we didn’t use them)
- No servers to buy
- No nginx to install
- No systemd unit to write
- No fail2ban to configure
- No disks to watch
Cloudflare Pages automatically pulls code from GitHub → runs pnpm build → pushes to 300+ edge nodes worldwide. Every git push main is a deployment.
_headers: caching policy
/_astro/*
Cache-Control: public, max-age=31536000, immutable
/assets/*
Cache-Control: public, max-age=31536000, immutable
/*
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
/_astro/* is Astro’s fingerprinted asset path, so it never expires; HTML goes through must-revalidate, so any push takes effect immediately.
_redirects: less is more
/*/ /:splat 301
We only do one thing: redirect /foo/ to /foo. Everything else is handled by Astro’s routing—no reason to add a CDN hop.
Security headers
X-Content-Type-Options: nosniff: blocks MIME sniffingReferrer-Policy: strict-origin-when-cross-origin: referer only sends to same-origin hostsStrict-Transport-Security: forces HTTPSPermissions-Policy: camera=(), microphone=(), geolocation=(): default-off every device API we don’t use
I didn’t add CSP. For a static site, CSP is mainly there to defend against XSS, and a static site has no user input. If you really want one, Content-Security-Policy: default-src 'self' is a fine start, then open up as needed.
When we want SSR
Cloudflare Pages comes with Functions (built on Workers). We currently don’t use them at all, but the interface is in place:
// functions/api/now.ts
export const onRequest = async () =>
new Response(JSON.stringify({ ok: true, ts: Date.now() }), {
headers: { 'content-type': 'application/json' },
});
/api/now becomes a Worker. If one day we want the Hero to pull real-time data, this is the entry point.
Deployment time
| Stage | Duration |
|---|---|
pnpm install | ~25s (~5s with cache hit) |
astro build | ~3s (10 pages) |
| Cloudflare edge push | ~10s |
Total from git push to globally visible: about 30 seconds.
There’s nothing cheaper than “deploy to production.”