Add Security Headers with Cloudflare Transform Rules
Add HTTP security headers in Cloudflare without touching your server. Includes a safe starting set, a careful HSTS and CSP rollout, and testing steps.
If your website sits behind Cloudflare, you can add security headers from the dashboard. You don't need server access, an .htaccess file or a developer deployment. This guide is for owners and whoever looks after their site.
You will learn how to create the rules, which headers to start with, and how to roll out the two risky ones (HSTS and CSP) without locking visitors out. If you're unsure what each header does, read security headers every small business website needs first. This article covers the "how".
In short: In Cloudflare, open the Rules section, create a Response Header Transform Rule and add one rule per header. Start with the low-risk ones and test after every change. Treat HSTS and Content-Security-Policy as staged projects, not one-click switches.
Before you start
- Your site is proxied. In DNS, the cloud icon next to your record should be orange ("Proxied"). Headers added in Cloudflare only apply to traffic that passes through Cloudflare.
- HTTPS works on every page and subdomain you care about. Cloudflare's Full (strict) SSL/TLS mode is the safest target if your server has a valid certificate.
- You can edit rules on that domain with your Cloudflare login.
Then record what visitors receive today. Open your site in Chrome or Edge, press F12, choose the Network tab, reload, click the first request and read Response Headers. Copy them into a note.
This matters because a Set static rule (the method used below) replaces your server's value for that header name. An Add static rule appends instead, and can leave you with a duplicate.
Creating a rule
Cloudflare moves menu items around now and then, so if a label differs, look for "Transform Rules". The usual steps are:
- Select your domain in the Cloudflare dashboard.
- Go to Rules and create a new rule.
- Choose Response Header Transform Rule.
- Enter a rule name, such as
Add nosniff header. - Under When incoming requests match, start narrow, for example only your main site:
(http.host eq "www.yourbusiness.com")
- Under Modify response header, choose Set static, then enter the header name and value.
- Click Deploy, or save as a draft if you want to come back to it.
We suggest one rule per header, so if something breaks you can switch off just that rule. Widen the match to other hostnames only after the first one is tested, because "all requests" can catch APIs and subdomains you didn't intend. Cloudflare's response header modification documentation lists the available operations and restrictions.
Watch out: Cloudflare also offers a Managed Transform called Add security headers, which switches on a preset group of headers with Cloudflare's own values. That preset includes
X-Frame-Optionsand a referrer policy ofsame-origin, which differs from the value in the table below, so mixing the two methods can leave you with conflicting settings. Pick one method per header.
A low-risk starting set
| Header | Value to enter | Check after deploying |
|---|---|---|
X-Content-Type-Options | nosniff | Scripts and styles still load |
Referrer-Policy | strict-origin-when-cross-origin | Analytics and forms still work |
Permissions-Policy | camera=(), microphone=(), geolocation=() | Allow what you use, e.g. geolocation=(self) |
X-Frame-Options | SAMEORIGIN | Booking widgets and other embeds |
Add them one at a time and test between each. These are low risk on most small business sites, but none is safe everywhere.
HSTS: go slowly
Strict-Transport-Security (HSTS) tells a browser to use HTTPS for your site automatically for a set period (max-age, in seconds). The danger is that browsers remember it.
- If your certificate expires while HSTS is active, visitors see an error and can't click through to the site.
- Turning off your Cloudflare rule does not clear what browsers have stored. To reverse HSTS you must serve
max-age=0over valid HTTPS and wait for each browser to receive it. includeSubDomainsextends the policy to every subdomain of the host that sent it.
A cautious rollout:
- Start with a one-day value:
max-age=86400. - Test forms, logins and checkout for a few days.
- Raise it to something like
max-age=15552000(about 180 days). - Add
includeSubDomainsonly when every subdomain, including old ones likemail.orshop., works over HTTPS. - Leave out
preloadfor now. It requires amax-ageof at least a year plusincludeSubDomains, and it is a long-term commitment to HTTPS everywhere.
Cloudflare also has a built-in HSTS setting on its Edge Certificates page, where the duration is chosen in months; 6 months is the closest match to the 180-day step. Choose either that setting or a Transform Rule, so you know which value is being sent. The MDN reference for HSTS explains each directive.
Content-Security-Policy: report first, enforce later
CSP lets you list which sources of scripts, images and frames your pages may use. It is the most powerful header here and the most likely to break something, so use two stages.
Stage 1: observe
Create a rule with the header name Content-Security-Policy-Report-Only and a value like this:
default-src 'self'; img-src 'self' data: https:; object-src 'none'; base-uri 'self'
Report-only mode blocks nothing, but it doesn't collect anything on its own either. Per the MDN page for Content-Security-Policy-Report-Only, violations are delivered through the Reporting API, and only when a reporting endpoint is configured (a report-to directive in the policy, matched by a Reporting-Endpoints header). Setting up somewhere to receive reports is a job for a developer or a reporting service, so decide where they will go first.
Keep in mind:
- The
sandboxdirective is ignored in report-only policies, so test that separately. - Reports only cover pages that get loaded. Test the homepage, contact form, checkout and login on desktop and mobile.
Treat each report as a question: do we actually need this resource? If yes, add its source to the right directive. If you don't recognise it, investigate before loosening the policy. Removing an unused tracker beats widening script-src. The sample above is a starting point and will flag many inline scripts and third-party tools, which is the point of observing.
Stage 2: enforce
When the important pages are quiet, add a second rule named Content-Security-Policy with your tuned value. Expect several passes on sites built with WordPress or similar platforms, where themes, plugins and analytics load from many places.
Removing headers that reveal your stack
Transform Rules can also remove response headers. If your server sends X-Powered-By (which can reveal the language or framework), create a response header transform rule, choose Remove and enter X-Powered-By. This is minor tidying, not protection by itself.
Test after every change
| Symptom | Likely cause | Fix |
|---|---|---|
| Header doesn't appear | Rule disabled or match doesn't fit | Check status and hostname/path match |
| Header appears twice | A rule uses Add static | Switch to Set static or remove the other source |
| Wrong value | Another rule overrides it | Check rule order |
| Old result | Browser cache | Retest with dev tools open and Disable cache ticked |
| Page features break | CSP or framing header too strict | Disable that one rule, then tune |
After each save:
- Load your homepage and a deeper page, then confirm the header in Response Headers on the main document.
- Check a redirect, a 404 page and an image or script file. Rules can match these differently.
- Click through forms, login, checkout, maps, chat widgets and embedded video.
- Look for blocked-resource messages in developer tools once a policy is enforced.
Tip: Keep a note of every rule you add, with the date and its value. When something breaks next month, you'll know what changed.
When Cloudflare isn't the right place
Edge rules suit sites that are fully proxied and want one place for site-wide headers. Set headers at the origin server instead if only part of your traffic is proxied, if your server already sends a carefully tuned CSP, or if headers must vary by page or by signed-in state.
Once your rules are live, the free Safe Scan at pentest.lordevo.com gives an outside view of your site's security headers. It can't test every route or logged-in workflow, so still click through your key pages yourself.
Key takeaways
- Confirm the site is proxied and HTTPS works before you begin.
- Create one rule per header, matched to one hostname at first, using Set static and one method per header.
- Start with
nosniff, a referrer policy, a permissions policy and a framing rule. - Begin HSTS at one day, raise it gradually, and delay
includeSubDomainsandpreload. - Run CSP in report-only mode with a reporting endpoint in place, then enforce.
- Test after every rule and keep notes so you can undo changes.
FAQ
Do I need a developer to do this?
Not for the simple headers. CSP on a complex site, including setting up a reporting endpoint, is where a developer's help pays off.
Will security headers make my site secure?
No. They add a layer of browser-side protection, but they don't replace updates, strong passwords or backups.
Can I use the same rules for subdomains?
Only once each subdomain has been tested. Widen the match step by step, and remember HSTS includeSubDomains affects all of them at once.
What if my site isn't on Cloudflare?
Set the same headers at your web server, hosting control panel or a plugin. The values and testing advice stay the same.