How to Conditionally Set HTTP Headers in Apache When Not Already Present


2 views

When working with Apache reverse proxy configurations, a common requirement is to set headers only when they're not already present. This becomes particularly important when:

  • Multiple layers of proxies might be injecting headers
  • Upstream services might provide their own headers
  • You want to avoid header duplication or overwrites

The solution lies in using RequestHeader setifempty instead of the regular set directive. Here's the improved configuration:

<Location /api>
    RequestHeader setifempty MY_HEADER "value"
    
    ProxyPass http://127.0.0.1:8000/api
    ProxyPassReverse http://127.0.0.1:8000/api
</Location>

For more complex conditional logic, you can combine multiple directives:

<If "%{HTTP:MY_HEADER} == ''">
    RequestHeader set MY_HEADER "default_value"
</If>

Or when dealing with response headers:

Header setifempty X-Custom-Header "backup_value"

Always verify your header behavior with curl:

curl -I http://your.server/api/some-endpoint

While conditional header logic is useful, remember:

  • Each conditional check adds minimal overhead
  • Complex expressions should be avoided in high-traffic scenarios
  • Consider using environment variables for dynamic values

When working with Apache reverse proxies, we often need to set custom headers before forwarding requests. However, blindly setting headers with RequestHeader set can overwrite existing headers, which might be problematic when:

  • Downstream services already set specific headers
  • Multiple proxy layers exist in your infrastructure
  • You want to respect original headers from clients

Apache provides the setifempty directive for this exact scenario. Here's how to modify your configuration:


<Location /api>
    # Only sets if header doesn't exist
    RequestHeader setifempty MY_HEADER "default_value"
    
    # Standard proxy configuration
    ProxyPass http://127.0.0.1:8000/api
    ProxyPassReverse http://127.0.0.1:8000/api
</Location>

For more complex conditions, you can use Apache's expr syntax:


<Location /api>
    # Only set header if not present
    RequestHeader set MY_HEADER "value" "expr=%{req:MY_HEADER} == ''"
    
    ProxyPass http://127.0.0.1:8000/api
    ProxyPassReverse http://127.0.0.1:8000/api
</Location>

To verify your conditional headers are working:

  1. curl -v http://your-server/api (without headers)
  2. curl -v -H "MY_HEADER: existing_value" http://your-server/api

The second request should preserve the original header value.

  • Security Headers: Only set X-Forwarded-For if not present
  • Debugging Headers: Add debug headers only when missing
  • Canary Deployments: Set routing headers conditionally

The setifempty directive has minimal overhead compared to regular header setting. The expr-based solution is slightly more resource-intensive but provides greater flexibility for complex conditions.