Keywords: Nginx | Reverse Proxy | Custom Response Headers | Upstream Server | Header Processing
Abstract: This article provides an in-depth exploration of how to read custom response headers from upstream servers (such as Apache) when using Nginx as a reverse proxy. By analyzing Nginx's four-layer header processing mechanism, it explains the usage scenarios of $upstream_http_* variables and clarifies the timing constraints of if directives. Practical configuration examples and best practices are provided to help developers properly handle custom header data.
In modern web architecture, Nginx plays a critical role as a reverse proxy server. A common requirement is reading custom header information from responses of upstream servers (such as Apache, Tomcat, or custom application servers). This article systematically analyzes this technical implementation through a concrete case study.
Problem Scenario and Core Challenges
Consider this typical scenario: Nginx acts as a reverse proxy, with a backend Apache server returning a response containing the custom header My-custom-header: 1. Developers need to read this value in Nginx configuration for conditional processing. Initial attempts might directly use the $sent_http_My_custom_header variable, but this may not work correctly in certain situations.
The Four-Layer Model of Nginx Header Processing
Understanding Nginx's header processing requires mastery of four key stages:
- Client to Nginx request headers: Accessed via
$http_namevariables - Nginx to upstream request headers: Set via
proxy_set_headerdirectives - Upstream to Nginx response headers: Accessed via
$upstream_http_namevariables - Nginx to client response headers: Accessed via
$sent_http_namevariables, set viaadd_headerdirectives
Correctly Accessing Upstream Response Headers
For custom headers returned by upstream servers, the $upstream_http_name variable format must be used. Hyphens in header names are converted to underscores. For example:
location / {
# Read My-custom-header from upstream
set $custom_value $upstream_http_My_custom_header;
# Use the value for subsequent processing
if ($custom_value = "1") {
# Note: Limitations of if directive here
}
}
Timing Constraints of if Directives
A critical limitation is that if directives execute during the rewrite phase, before upstream responses are received. Therefore, directly checking $upstream_http_* variables in if is ineffective. Solutions include:
- Using
mapdirectives for response-phase processing:map $upstream_http_My_custom_header $custom_flag { default 0; "1" 1; } server { location / { # Use $custom_flag in response-phase directives like add_header add_header X-Custom-Flag $custom_flag; } } - Using Lua module for complex processing:
header_filter_by_lua_block { local custom_header = ngx.var.upstream_http_My_custom_header if custom_header == "1" then ngx.header["X-Processed"] = "true" end }
Practical Configuration Example
The following complete configuration demonstrates how to read upstream custom headers and add response headers based on their values:
http {
# Define mapping relationships
map $upstream_http_My_custom_header $response_category {
default "unknown";
"1" "premium";
"2" "standard";
}
server {
listen 80;
location /api/ {
proxy_pass http://backend_server;
# Preserve upstream custom header (optional)
proxy_pass_header My-custom-header;
# Add new header based on upstream header value
add_header X-Response-Category $response_category;
# Logging
access_log /var/log/nginx/access.log custom_format;
}
}
# Custom log format including upstream header
log_format custom_format '$remote_addr - $upstream_http_My_custom_header';
}
Header Passing and Copying Mechanisms
Nginx does not pass all upstream response headers to clients by default. The proxy_pass_header directive explicitly passes specific headers, while proxy_hide_header hides headers. Understanding this mechanism is crucial for maintaining secure header policies.
Debugging and Validation Techniques
Methods for verifying configuration correctness include:
- Adding debug headers in Nginx configuration:
add_header X-Upstream-Header $upstream_http_My_custom_header; - Using
curl -Ito inspect response headers - Checking Nginx error logs:
tail -f /var/log/nginx/error.log
By systematically understanding Nginx's header processing mechanism, developers can flexibly handle various custom header scenarios and build more robust reverse proxy architectures.