NGINX Proxy Pass Not Forwarding Custom Headers: Solutions & Best Practices


2 views

When using NGINX as a reverse proxy, developers often encounter header forwarding issues. In this specific case:

  • Original header USER_CUSTOMER works in direct API calls
  • Header becomes NULL when routed through NGINX proxy
  • Hardcoded headers via proxy_set_header work, but dynamic values are needed

By default, NGINX only forwards certain headers when using proxy_pass:

location /api {
    proxy_pass https://myapp.herokuapp.com;
    rewrite ^/api/(.*) /$1 break;
}

This configuration will strip custom headers unless explicitly told to preserve them.

To properly forward all headers including custom ones:

location /api {
    proxy_pass https://myapp.herokuapp.com;
    proxy_pass_request_headers on;
    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 USER_CUSTOMER $http_user_customer;
    rewrite ^/api/(.*) /$1 break;
}

For more complex scenarios:

# Forward all headers dynamically
map $http_user_customer $user_customer {
    default $http_user_customer;
    ""      $sent_http_user_customer;
}

server {
    location /api {
        proxy_pass https://myapp.herokuapp.com;
        proxy_set_header USER_CUSTOMER $user_customer;
        proxy_set_header Authorization $http_authorization;
        proxy_pass_request_headers on;
        proxy_set_header X-Original-URI $request_uri;
    }
}

Diagnose header issues with these methods:

  1. Check NGINX access logs: tail -f /var/log/nginx/access.log
  2. Use curl with verbose output: curl -v -H "USER_CUSTOMER: test123" http://yourproxy/api/endpoint
  3. Inspect headers at the destination server

When forwarding many headers:

  • Enable buffer optimization: proxy_buffer_size 4k;
  • Consider header size limits: proxy_headers_hash_max_size 512;
  • For HTTP/2 connections: proxy_http_version 2;

location /api {
    proxy_pass              https://myapp.herokuapp.com;
    rewrite                 ^/api/(.*)              /$1     break;
}

When working with NGINX as a reverse proxy, you might encounter situations where custom headers (like USER_CUSTOMER) mysteriously disappear during proxy_pass. This happens because NGINX has specific rules about which headers get forwarded by default.

NGINX automatically forwards these standard headers by default:

  • Host
  • Connection
  • X-Real-IP
  • X-Forwarded-For
  • X-Forwarded-Proto

Custom headers like USER_CUSTOMER need explicit configuration.

To preserve custom headers, you have three approaches:

# Option 1: Forward specific header
location /api {
    proxy_pass              https://app.herokuapp.com;
    proxy_set_header        USER_CUSTOMER           $http_user_customer;
    rewrite                 ^/api/(.*)              /$1     break;
}

# Option 2: Forward all headers (careful with sensitive data)
location /api {
    proxy_pass              https://app.herokuapp.com;
    proxy_pass_request_headers      on;
    rewrite                 ^/api/(.*)              /$1     break;
}

# Option 3: Forward multiple specific headers
location /api {
    proxy_pass              https://app.herokuapp.com;
    proxy_set_header        USER_CUSTOMER           $http_user_customer;
    proxy_set_header        X-Another-Header        $http_x_another_header;
    rewrite                 ^/api/(.*)              /$1     break;
}

1. Header name transformation: NGINX converts headers to uppercase and replaces hyphens with underscores when accessing them as variables ($http_*).
2. Security implications of forwarding all headers
3. Header case sensitivity in your backend application

Add these directives to help troubleshoot:

log_format headers '$remote_addr - $remote_user [$time_local] '
                   '"$request" $status $body_bytes_sent '
                   '"$http_referer" "$http_user_agent" "$http_user_customer"';

access_log /var/log/nginx/headers.log headers;

This will help verify if the header is reaching NGINX before being forwarded.

For most use cases, this is the recommended approach:

location /api {
    proxy_pass              https://app.herokuapp.com;
    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        USER_CUSTOMER           $http_user_customer;
    proxy_set_header        X-Forwarded-Proto       $scheme;
    rewrite                 ^/api/(.*)              /$1     break;
}