Many developers encounter this issue when trying to conditionally set headers based on request characteristics. Nginx explicitly prohibits proxy_set_header
directives inside if
blocks due to its internal processing architecture.
# This will FAIL
location / {
if ($http_cookie ~* "mycookie") {
proxy_set_header X-Custom "value"; # Not allowed here
proxy_pass http://backend;
}
}
The restriction exists because Nginx processes directives in specific phases during request handling. Header modifications must occur during the rewrite phase, while if
blocks create new configuration contexts with different phase timing.
Here are three reliable approaches to achieve conditional header setting:
1. Using map Directive
map $http_cookie $custom_header {
default "";
~*mycookie $request;
}
server {
listen 8080;
location / {
proxy_set_header X-Request $custom_header;
if ($http_cookie ~* "mycookie") {
proxy_pass http://localhost:8081;
}
}
}
2. Separate Location Blocks
server {
listen 8080;
location = /check-cookie {
internal;
if ($http_cookie ~* "mycookie") {
return 200 "1";
}
return 200 "0";
}
location / {
auth_request /check-cookie;
proxy_set_header X-Request $request;
proxy_pass http://localhost:8081;
}
}
3. Using Lua Module (if available)
location / {
access_by_lua_block {
if ngx.var.http_cookie:match("mycookie") then
ngx.req.set_header("X-Request", ngx.var.request)
end
}
proxy_pass http://localhost:8081;
}
The map
solution is generally most efficient for simple cases, while the Lua approach offers maximum flexibility. Avoid complex if-based routing when possible as it can impact performance.
This pattern becomes particularly useful for:
- A/B testing header injection
- Conditional CORS headers
- Request tracing based on specific cookies
- Dynamic upstream routing
Many developers encounter this puzzling behavior when trying to conditionally set headers in Nginx configurations. The error message clearly states that proxy_set_header
isn't allowed within if
blocks, but doesn't explain why.
# This fails with "directive not allowed" error
if ($condition) {
proxy_set_header X-Custom-Header "value";
}
Nginx processes configuration directives in distinct phases during request handling. The if
block creates a new context with specific limitations:
- Rewrite phase directives (like
set
,if
) can be used - Access phase directives (like
auth_basic
) can be used - Content phase directives (like
proxy_set_header
) cannot be used
Here are effective solutions to achieve conditional header setting:
1. Map Module Solution
map $http_cookie $custom_header {
default "";
"~*mycookie" $request;
}
server {
location / {
proxy_set_header X-Request $custom_header;
proxy_pass http://backend;
}
}
2. Separate Location Blocks
server {
location / {
if ($http_cookie ~* "mycookie") {
rewrite ^ /special last;
}
proxy_pass http://backend_default;
}
location = /special {
internal;
proxy_set_header X-Request $request;
proxy_pass http://backend_special;
}
}
3. Lua Module (OpenResty)
location / {
access_by_lua_block {
if ngx.var.http_cookie:match("mycookie") then
ngx.req.set_header("X-Request", ngx.var.request)
end
}
proxy_pass http://backend;
}
The fundamental reason lies in how Nginx merges configurations. When processing if
blocks, Nginx creates a pseudo-location that inherits most directives from the parent context but restricts certain operations for performance and safety reasons.
While the workarounds work, each has performance implications:
- The
map
solution adds minimal overhead - Separate locations may cause additional internal redirects
- Lua module requires OpenResty and adds scripting overhead