Cloudflare Pages Security: Headers, HTTPS, and CSP Configuration
Cloudflare Pages security is built around a simple but powerful mechanism: the _headers file. Placed at the root of your project, this file instructs Cloudflare's edge network to add specific HTTP response headers to your pages — no server configuration, no build plugins, no environment variables required.
This guide gives you everything you need: a production-ready _headers file, HTTPS configuration, a Content Security Policy you can actually use, and cache-control settings that balance performance with security.
Scan your Cloudflare Pages site with ZeriFlow before and after applying these changes to measure the security improvement.
The _headers File: How It Works
Cloudflare Pages looks for a file named _headers in the root of your output directory (the directory you deploy, not your source directory). For a React or Vue project, this is typically build/, dist/, or public/. The file must be included in your deployment — add it to your build process or place it in your public/ folder so your build tool copies it automatically.
The syntax is simple:
/path/or/pattern
Header-Name: header-value
Another-Header: valuePaths support wildcard patterns. /* matches all routes.
Where to place the file:
- Next.js: public/_headers
- Create React App: public/_headers
- Vue CLI: public/_headers
- Astro: public/_headers
- Plain HTML: root of your project
Complete Production-Ready _headers File
Copy and paste this into your project's public/_headers file:
/*
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: geolocation=(), microphone=(), camera=(), payment=(), usb=(), interest-cohort=()
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' https://fonts.gstatic.com; connect-src 'self' https://api.yourdomain.com; frame-ancestors 'none';
/assets/*
Cache-Control: public, max-age=31536000, immutable
/*.js
Cache-Control: public, max-age=31536000, immutable
/*.css
Cache-Control: public, max-age=31536000, immutable
/
Cache-Control: public, max-age=0, must-revalidate
/*.html
Cache-Control: public, max-age=0, must-revalidateWhat each section does:
The /* block applies security headers to every response. The /assets/*, /*.js, and /*.css blocks set aggressive caching for static assets (which should have content-hashed filenames). The / and /*.html blocks disable caching for HTML files so users always get the latest version of your app.
HTTPS Configuration on Cloudflare Pages
Cloudflare Pages provides HTTPS automatically on all .pages.dev subdomains and on custom domains. However, there are a few settings worth verifying:
Automatic HTTPS rewrites: In your Cloudflare dashboard → your Pages project → Settings → Environment Variables — there is no toggle here, but in your domain's main Cloudflare DNS settings (if you have your domain on Cloudflare): 1. Go to SSL/TLS → Edge Certificates. 2. Enable Always Use HTTPS. 3. Enable Automatic HTTPS Rewrites.
HSTS in your _headers file:
The Strict-Transport-Security header in your _headers file ensures that even if a visitor's browser somehow ends up on HTTP, it will be automatically redirected to HTTPS by the browser itself — not just by Cloudflare.
Custom domain HTTPS:
When you add a custom domain to Cloudflare Pages:
1. Cloudflare automatically provisions a TLS certificate via Let's Encrypt or their own CA.
2. The certificate is active within minutes of DNS propagation.
3. No action is required on your part — but verify the certificate is valid by checking https://yourdomain.com immediately after DNS propagates.
Content Security Policy: Tuning for Your Stack
The CSP in the template above is a starting point. You will need to tune the script-src and connect-src directives for your specific application. Here are common additions by stack:
Google Analytics / Google Tag Manager:
script-src 'self' 'unsafe-inline' https://www.googletagmanager.com https://www.google-analytics.com;
img-src 'self' data: https: https://www.google-analytics.com;
connect-src 'self' https://www.google-analytics.com;Stripe payment integration:
script-src 'self' 'unsafe-inline' https://js.stripe.com;
frame-src https://js.stripe.com;
connect-src 'self' https://api.stripe.com;Intercom or HubSpot chat:
script-src 'self' 'unsafe-inline' https://widget.intercom.io https://js.intercomcdn.com;
connect-src 'self' https://api.intercom.io https://api-iam.intercom.io;Testing your CSP without breaking your site:
Instead of Content-Security-Policy, use Content-Security-Policy-Report-Only in your _headers file during development:
/*
Content-Security-Policy-Report-Only: default-src 'self'; report-uri https://your-csp-report-endpoint.com;This sends violation reports without blocking anything. Review the reports for 24 hours, add the missing sources to your policy, then switch to enforcement mode.
Cache-Control: Security Considerations
Cache-control is usually thought of as a performance concern, but it has security implications too:
Sensitive pages (account settings, checkout, admin):
/account/*
Cache-Control: private, no-store
/admin/*
Cache-Control: private, no-storeno-store prevents both browser and CDN caching of sensitive responses. This is important for pages that contain personal data, tokens, or session-specific content.
API responses proxied through Pages Functions:
/api/*
Cache-Control: no-store
Content-Security-Policy: default-src 'none'API endpoints should generally not be cached and do not need document-level CSP. default-src 'none' is the most restrictive policy.
Verifying With ZeriFlow
Once your _headers file is deployed, run a ZeriFlow security scan on your Cloudflare Pages URL to confirm:
- All security headers are present and correctly formatted
- HSTS is configured with a sufficient max-age
- CSP is present and does not contain obvious weaknesses
- HTTPS redirect is working
- Cache-Control is set appropriately for your HTML pages
ZeriFlow checks the actual HTTP responses returned by your site, which is the only reliable way to verify that your _headers file is being applied correctly after deployment.
FAQ
### Q: Does the _headers file work with Cloudflare Pages Functions?
A: Yes, but Functions-generated responses can override _headers directives. If your Pages Function sets a response header explicitly, it will take precedence over the _headers file for that path. For headers that should apply everywhere, set them in your Function using the Response object, or use the _headers file and avoid conflicting header assignments in your Functions.
### Q: Can I use environment-specific headers in Cloudflare Pages?
A: The _headers file does not support environment variables — it is a static file. For environment-specific headers, use a build step to generate the _headers file from a template, injecting environment-specific values during the build process.
### Q: Why does Cache-Control: immutable matter for JS and CSS?
A: The immutable directive tells the browser that the resource will never change — so even if the user refreshes the page, the browser will not re-request the file as long as it is within the max-age window. This improves performance significantly. It is safe only when your JS and CSS files have content-hashed filenames (e.g., app.3f7d9a.js) that change with every new build.
### Q: Does Cloudflare Pages support HSTS preloading?
A: Yes. Once your site has been on HTTPS for a period and you have set Strict-Transport-Security: max-age=31536000; includeSubDomains; preload, you can submit your domain to the HSTS preload list at hstspreload.org. This embeds your domain in browsers' hard-coded HTTPS-only list — once submitted, it takes months to remove, so only do this if you are committed to HTTPS permanently.
Conclusion
Cloudflare Pages security configuration requires no server access, no complex tooling, and no paid features. A single _headers file, correctly configured, activates the full set of browser security mechanisms: HSTS, CSP, clickjacking protection, MIME sniffing protection, and referrer policy.
The five minutes it takes to add this file to your project is one of the highest-leverage security investments you can make for a static or Jamstack application.
Verify your Cloudflare Pages security with ZeriFlow — the free scan confirms every header is in place and flags any misconfigurations before they become vulnerabilities.