How to Forward Custom Headers (X-CUSTOM-REFERRER) Through Nginx Reverse Proxy to Apache Backend


2 views

When working with Nginx as a reverse proxy, a common requirement is forwarding custom headers to backend servers like Apache. The default Nginx configuration only passes standard headers, dropping any custom ones like X-CUSTOM-REFERRER unless explicitly configured.

For forwarding specific headers, use proxy_set_header directives:

location / {
    proxy_pass http://apache_backend;
    proxy_set_header X-CUSTOM-REFERRER $http_x_custom_referrer;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

For a more flexible solution that forwards all incoming headers:

location / {
    proxy_pass http://apache_backend;
    proxy_pass_request_headers on;
    
    # Forward all headers that start with 'X-'
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Host $host;
    
    # Capture all custom headers
    more_set_input_headers 'X-: $http_x_';
    more_set_headers 'X-: $sent_http_x_';
}

1. The $http_ prefix converts headers to variables (dashes become underscores)
2. For the dynamic solution, you may need the headers-more-nginx-module
3. Always verify headers reach Apache using:

curl -I -H "X-CUSTOM-REFERRER: testvalue" http://yourdomain.com

If headers aren't appearing in Apache:
- Check Nginx error logs for header processing issues
- Verify no other Nginx rules are modifying headers
- Test with tcpdump between Nginx and Apache
- Add this to Apache config to log all headers:

LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\" %{X-CUSTOM-REFERRER}i" combined

When forwarding numerous headers:
- Large headers increase memory usage
- Each proxy_set_header adds processing overhead
- Consider whitelisting only necessary headers in production


When working with Nginx as a reverse proxy, one common requirement is forwarding custom HTTP headers to backend servers like Apache. Many developers struggle with this because:

  • Nginx doesn't forward non-standard headers by default
  • The proxy_set_header directive can be tricky to configure properly
  • Header names might get normalized (e.g., underscores removed)

For your specific case with X-CUSTOM-REFERRER, here's how to modify your config:

location / {
    proxy_pass                  http://preview;
    proxy_redirect              off;
    proxy_set_header            Host $host;
    proxy_set_header            X-Real-IP $remote_addr;
    proxy_set_header            X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header            X-Custom-Referrer $http_x_custom_referrer;
}

Key points about this solution:

  • Use $http_ prefix followed by the header name (lowercase, with hyphens replaced by underscores)
  • The header name in proxy_set_header can be different from the original header name
  • Nginx automatically normalizes header names in variables

If you need to forward all incoming headers automatically, you'll need a more advanced solution:

location / {
    proxy_pass http://preview;
    
    # Preserve original headers
    proxy_pass_request_headers on;
    
    # Forward all headers that start with X- or x-
    proxy_set_header X-Forwarded-Proto $scheme;
    
    # Special handling for headers with underscores
    underscores_in_headers on;
    
    # Forward specific headers you know about
    proxy_set_header X-Custom-Referrer $http_x_custom_referrer;
    
    # Forward arbitrary headers (requires Nginx 1.13.8+)
    proxy_set_header "$header_name" "$http_header_name";
}

When header forwarding doesn't work as expected:

  • Check for underscores in header names (enable underscores_in_headers)
  • Verify the header reaches Nginx (check access logs)
  • Inspect Apache's received headers using:
# Apache config to log headers
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{X-Custom-Referrer}i\"" custom
CustomLog /var/log/apache2/access.log custom

While forwarding all headers might seem convenient, it has implications:

  • Increased memory usage for each request
  • Potential security risks from forwarding unnecessary headers
  • Header size limitations (configure with proxy_buffer_size)

For most production environments, explicitly listing required headers offers better security and performance.

Sometimes you need context-aware forwarding. Here's an example using map:

map $http_x_special_header $should_forward {
    default 0;
    "special-value" 1;
}

server {
    location / {
        proxy_pass http://backend;
        
        if ($should_forward) {
            proxy_set_header X-Special-Header $http_x_special_header;
        }
    }
}