If your site runs behind Cloudflare's proxy (orange cloud), you can add security headers at the edge without touching your origin server. Cloudflare offers three approaches:Transform Rules (no code, dashboard-only), Workers (full control with JavaScript), and the _headers file for Cloudflare Pages static deployments.
Method 1: Transform Rules (No Code)
Transform Rules let you modify HTTP response headers through the Cloudflare dashboard without writing any code. This is the easiest option for adding all security headers.
Creating a Transform Rule
- Log in to the Cloudflare dashboard and select your domain.
- Go to Rules → Transform Rules.
- Click Create rule and select Modify Response Header.
- Give the rule a name, e.g., Security Headers.
- Under If, set the expression to match all requests:text
(http.request.uri.path contains "/") - Under Then, click Add for each header below.
- Set Operation to Set.
- Click Deploy when done.
Add the following headers one by one:
| Header Name | Value |
|---|---|
Strict-Transport-Security | max-age=31536000; includeSubDomains; preload |
Content-Security-Policy | default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self' |
X-Frame-Options | DENY |
X-Content-Type-Options | nosniff |
Referrer-Policy | strict-origin-when-cross-origin |
Permissions-Policy | camera=(), microphone=(), geolocation=(), fullscreen=(self), payment=() |
X-XSS-Protection | 0 |
Method 2: Cloudflare Workers
Cloudflare Workers give you full programmatic control over requests and responses. Use this method if you need conditional logic — for example, applying a stricter CSP on specific paths.
// worker.js
export default {
async fetch(request, env) {
// Forward the request to your origin
const response = await fetch(request);
// Clone the response so we can modify headers
const newResponse = new Response(response.body, response);
// ── Security Headers ──────────────────────────────────────────────
newResponse.headers.set(
'Strict-Transport-Security',
'max-age=31536000; includeSubDomains; preload'
);
newResponse.headers.set(
'Content-Security-Policy',
"default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'"
);
newResponse.headers.set('X-Frame-Options', 'DENY');
newResponse.headers.set('X-Content-Type-Options', 'nosniff');
newResponse.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin');
newResponse.headers.set(
'Permissions-Policy',
'camera=(), microphone=(), geolocation=(), fullscreen=(self), payment=()'
);
newResponse.headers.set('X-XSS-Protection', '0');
// Remove server fingerprinting headers
newResponse.headers.delete('Server');
newResponse.headers.delete('X-Powered-By');
// ── End Security Headers ──────────────────────────────────────────
return newResponse;
},
};Deploy with Wrangler:
# Install Wrangler CLI
npm install -g wrangler
# Authenticate
wrangler login
# Deploy the Worker
wrangler deployWrangler Configuration (wrangler.toml)
name = "security-headers"
main = "worker.js"
compatibility_date = "2024-01-01"
routes = [
{ pattern = "example.com/*", zone_name = "example.com" }
]Method 3: Cloudflare Pages _headers File
For static sites deployed to Cloudflare Pages, you can define response headers in a _headers file placed in the root of your build output directory. No dashboard configuration required.
# _headers
# Apply security headers to all routes
/*
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=(), fullscreen=(self), payment=()
X-XSS-Protection: 0Place this file in your public/ or dist/ folder (whichever is your build output directory). Cloudflare Pages reads it automatically during deployment.
_headers file supports multiple route patterns. Add more specific routes below the /* wildcard to override headers for particular paths:/*
X-Frame-Options: DENY
# Allow iframes on the embed page only
/embed/*
X-Frame-Options: SAMEORIGINHSTS via Cloudflare SSL/TLS Settings
Cloudflare also has a dedicated HSTS toggle separate from Transform Rules:
- Go to SSL/TLS → Edge Certificates.
- Scroll to HTTP Strict Transport Security (HSTS).
- Click Enable HSTS.
- Set
Max Age Headerto12 months (recommended). - Toggle Apply HSTS policy to subdomains and Preload as appropriate.
- Click Save.
If you use this dedicated panel for HSTS, do not also add it via Transform Rules or Workers to avoid sending a duplicate Strict-Transport-Security header.
Verifying Headers
# Check headers with curl
curl -I https://example.com
# Expected output includes:
# strict-transport-security: max-age=31536000; includeSubDomains; preload
# content-security-policy: default-src 'self'; ...
# x-frame-options: DENY
# x-content-type-options: nosniff
# referrer-policy: strict-origin-when-cross-origin
# permissions-policy: camera=(), microphone=(), ...
# x-xss-protection: 0Or use the ShowDNS Security Headers Scanner for a full graded report.
Frequently Asked Questions
Do I still need to set headers on my origin server?
If Cloudflare's proxy is always in front of your site, you can manage headers purely at the Cloudflare edge. However, setting them on the origin server as well is good practice for defence in depth — it protects traffic in scenarios where Cloudflare is bypassed or a record temporarily switches to DNS-only mode.
Will Cloudflare's headers conflict with my origin's headers?
If both your origin and Cloudflare Transform Rules set the same header, the browser will receive duplicate headers. Use the Override operation in Transform Rules (rather than Set) to replace the origin value, or remove the header from your origin configuration when managing it through Cloudflare.
Does the free Cloudflare plan support Transform Rules?
Yes. Transform Rules (Modify Response Header) are available on the free plan with a limit of 10 rules. All seven security headers can be added in a single rule with multiple header operations, counting as just one rule.