Header Rules
A header rule edits HTTP headers at the edge: on the request before nsin forwards it to your server, on the response before it reaches the visitor, or both from the same rule. Nothing on your server has to change.
Use one when you want a header your application doesn’t send — a
Content-Security-Policy, an X-Frame-Options, a shared secret that proves the
request came through nsin — or when you want a header your application does
send to go away before anyone sees it.
The two directions
Section titled “The two directions”| Applied | Your server sees it | The visitor sees it | |
|---|---|---|---|
| Request | Before nsin calls your server | Yes | No |
| Response | Before the answer leaves the edge | No | Yes |
One rule can carry operations in both directions.
Response edits happen after the cache, not before it. That means a cached page gets the headers your rule says today, and editing a rule shows up on the very next request — you never have to purge the cache to change a response header.
The operations
Section titled “The operations”A rule is an ordered list of operations. Each one names a direction, an action, a header and (for the first two) a value.
| Action | What it does |
|---|---|
| Set | Replace whatever is there with your value. Use this when you want exactly one value. |
| Add | Append your value, keeping anything the client or your server already sent. |
| Remove | Delete the header entirely. Takes no value. |
Operations run in the order you list them, so a later one wins over an earlier one on the same header name.
Removing a group of headers at once
Section titled “Removing a group of headers at once”A remove operation may end in *: X-Debug-* deletes every header starting
with X-Debug-. This is the only place a wildcard is allowed — set and add
need one exact name to write to.
The reserved list below is re-checked against every header a wildcard actually matches, so a broad pattern can never strip a header nsin owns.
Rules add up
Section titled “Rules add up”This is the one rule type where every matching rule runs. Everywhere else in nsin the first matching rule wins and the rest are skipped.
Headers work better that way: a zone-wide “my security headers” rule plus a
small rule that adds one more header on /admin is the normal shape, and
first-match-wins would force you to copy the zone-wide set into every path rule.
When two rules write the same header name, the one lower in the list wins — it runs last. Drag the list to change that.
Like every rule, a header rule can be narrowed by records, hostname and path — see Rules Overview.
Two limits are specific to this type:
- Visitor IP scope is only available on response-only rules. A request header changes what nsin fetches from your server without changing what the cache stores it under, so the copy fetched for one visitor’s IP would be served to everyone else. Response edits happen per request, after the cache, so they keep the full IP scope.
- Gateway records are not eligible. One gateway hostname fronts many customers’ upstreams, so a rule that stamps a credential header there would reach somebody else’s traffic.
Dry run
Section titled “Dry run”A header rule can be saved in dry run. The rule still matches and is still recorded, but the request and the response both pass through untouched. Use it to confirm a broad rule is catching what you meant before it changes anything.
Limits
Section titled “Limits”| Limit | Value |
|---|---|
| Operations per rule | 16 |
| Length of one value | 4 KB |
| Total added per rule | 8 KB (name + value of every set/add) |
4 KB is room for a real Content-Security-Policy while staying under the 8 KB
per-header limit that nginx and Apache default to. All three are checked when
you save, so an oversized rule fails with a clear message instead of turning
into a 431 from your own server later.
Header rules compose — every rule that matches applies, not just the first —
so the total a request actually carries is the sum over all matching rules. The
edge caps that composed total at 8 KB per direction as well, and drops the ops
that would go over it, so a stack of rules can never turn into a 431 either.
Removals never count toward the cap and are never dropped.
Headers you can’t change, and why
Section titled “Headers you can’t change, and why”nsin refuses a small set of names — not to be awkward, but because the edge is already the thing that computes them, and a hand-written value would either be ignored or would break something quietly. The check is per direction and per action, so a name can be refused for one action and allowed for another.
Every refusal comes back as a 400 naming the header and the reason.
On the request:
| Header | Why |
|---|---|
Host | It isn’t an ordinary header at the edge — it also picks the TLS name and the cache slot. Override it on the record, or on an origin route or pool, where it is validated against your zone. |
Content-Length | Recomputed from the bytes actually forwarded, and read as a signal for whether a body can be buffered. A wrong value can store a truncated page. |
Transfer-Encoding, Connection, Upgrade, Keep-Alive, Proxy-Connection, TE, Trailer | Hop-by-hop: they describe the connection between the visitor and the edge, and never travel further anyway. |
X-Forwarded-For, X-Forwarded-Proto, X-Forwarded-Host, X-Forwarded-Port, X-Real-IP, True-Client-IP, Forwarded | nsin fills these from the connection it actually accepted. A fixed value is a way to hand your server a fake visitor address. |
CDN-Loop | The loop counter other CDNs read. Forwarding a foreign marker to a CDN-fronted origin is a confirmed way to earn a 502. |
Cache-Control, If-None-Match, If-Modified-Since, If-Match, If-Range, Range, Accept-Encoding | The edge rewrites this set differently on each of its fetch paths, so one rule would behave three different ways. |
Sec-WebSocket-* | Supplying a handshake key by rule would defeat the tunnel detection that reads it. |
Nsn-*, X-Nsin-*, X-Mafar-* | nsin’s own namespace. Origins trust these, so a rule that could write one is a forgery. |
On the response:
| Header | Why |
|---|---|
Content-Length | Recomputed from the bytes actually written. |
Transfer-Encoding, Connection, Upgrade, Keep-Alive | Hop-by-hop again. |
Content-Encoding | Owned by the edge’s compressor. What’s stored is always uncompressed, and a stored value is never replayed. |
Vary | The cache doesn’t key on it, so declaring a variance nsin won’t honour is a way to serve one visitor’s page to another. |
Server | Stamped last, deliberately, as the final change before the response goes out. |
Strict-Transport-Security | HSTS can’t be taken back once a browser has seen it, so it belongs to the ramp on Security → HSTS, which raises the duration one step per save. See Security Headers. |
Nsn-* | nsin’s own analytics and diagnostics surface. |
The exception: you may remove them
Section titled “The exception: you may remove them”Three request headers are refused for set and add but allowed for
remove: Cookie, Authorization and Nsn-Connecting-IP.
The reason they’re blocked is that nsin strips credentials before it refreshes a cached page, and a rule that put one back afterwards would store somebody’s personalised page in the slot everybody shares. A remove can’t do that — it can only agree with the strip.
And stripping is genuinely useful: dropping Cookie before the request reaches
your server is how you make a page cacheable that otherwise wouldn’t be, and
dropping Nsn-Connecting-IP before a third-party origin keeps your visitors’
addresses to yourself.
Headers nsin manages for you
Section titled “Headers nsin manages for you”Some headers are a switch rather than a text box, because getting them wrong is expensive:
X-Content-Type-Options,Referrer-Policyand the fingerprint strip are per-domain toggles — see Security Headers.Strict-Transport-Securityand the minimum TLS version live on Security → HSTS for the same reason.- The headers nsin always adds to proxied traffic, such as
Nsn-Connecting-IP, are listed in Proxy Headers.
Header rules are for your headers. Those pages are for nsin’s.
What a header rule cannot reach
Section titled “What a header rule cannot reach”- Your own rules. Header rules run last, after the WAF, bot detection, fingerprinting and rewrites. A request header you add is not visible to any of them — deliberately, so a rule can’t be used to slip past your own protection or to trip it.
- WebSocket upgrades. A
101handshake doesn’t pass the point where response headers are applied, so response operations don’t affect it. Request operations do. - nsin’s own pages. Error pages, challenge pages, the basic-auth prompt and block responses come from the edge, not your server, and your rules don’t touch them.
Examples
Section titled “Examples”Security headers for the whole site
- Response · set ·
X-Frame-Options·SAMEORIGIN- Response · set ·
X-XSS-Protection·0- Response · set ·
Permissions-Policy·camera=(), microphone=()
Prove to your server that traffic came through nsin
- Request · set ·
X-Edge-Secret·a-long-random-stringThen have your server refuse anything without it — the same idea as only trusting nsin’s proxy headers on traffic that really came from the edge.
Make a marketing page cacheable
- Path:
/landing/*- Request · remove ·
CookieYour server stops seeing a session for those pages, so it stops personalising them, so they can be cached for everyone.
Stop leaking your framework
- Response · remove ·
X-Powered-By- Response · remove ·
X-AspNet-*
Common questions
Section titled “Common questions”I added a response header but I don’t see it. Check the record is proxied — rules only run for traffic through nsin. If it is, check the rule isn’t in dry run, and remember that error pages and challenge pages come from nsin rather than your server.
Do I have to purge the cache after changing a response header? No. Response headers are applied after the cache, so the change is live on the next request.
Two rules set the same header. Which wins? The one lower in the list — it runs last. See the order of rules.
Can I use the visitor’s country or the ray id as a value? Not yet. Values are fixed text today.
Can a header rule replace my origin’s CORS or CSP setup? It can add or override those headers, and for a static site that’s often simplest. If your application already computes them per response, leave it to the application — an edge rule would flatten every response to one value.