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:
- Check NGINX access logs:
tail -f /var/log/nginx/access.log
- Use curl with verbose output:
curl -v -H "USER_CUSTOMER: test123" http://yourproxy/api/endpoint
- 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;
}