In Nginx reverse proxy configurations, proxy_set_header
directives modify or add HTTP headers before forwarding requests to backend servers. While technically optional, these headers provide critical information flow between client, proxy, and application servers.
# Essential headers for proper reverse proxying
location / {
# Preserves original client IP (crucial for logging/auth)
proxy_set_header X-Real-IP $remote_addr;
# Tracks full proxy chain for debugging
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# Maintains original Host header (vital for virtual hosting)
proxy_set_header Host $http_host;
# Custom header indicating Nginx proxy involvement
proxy_set_header X-NginX-Proxy true;
proxy_pass http://backend_app;
}
X-Real-IP: Without this, your Node.js app would only see Nginx's IP address. Essential for:
- Rate limiting
- Geo-based features
- Security logging
X-Forwarded-For: Builds a chain of proxy IPs when requests pass through multiple hops. Example format:
X-Forwarded-For: client_ip, proxy1_ip, proxy2_ip
Host Header: Critical when hosting multiple subdomains. Without it, your backend receives requests for http://localhost:3000
instead of http://api.yourdomain.com
.
For WebSocket applications or custom auth flows:
location /ws/ {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Special-Auth $http_x_special_auth;
proxy_pass http://websocket_backend;
}
While you can omit headers, benchmark tests show:
- With headers: 12% CPU overhead
- Without headers: 9% CPU overhead
The minimal performance gain rarely justifies losing critical request metadata.
Problem: App shows 127.0.0.1 for all users
Fix: Ensure X-Real-IP
exists and your app reads it properly
Problem: Subdomains not routing correctly
Fix: Verify Host
header preservation and server_name configuration
Always sanitize incoming headers in your Node.js application:
// In Express.js
app.enable('trust proxy'); // Required for X-Forwarded-*
app.use((req, res, next) => {
if(!req.headers['x-nginx-proxy']) {
return res.status(403).send('Direct access forbidden');
}
next();
});
When setting up Nginx as a reverse proxy for Node.js applications, the proxy_set_header
directive plays a crucial role in preserving client information and ensuring proper application functionality. While proxy_pass
is indeed the minimum requirement, these headers solve important real-world problems that emerge in production environments.
location / {
# Preserves original client IP
proxy_set_header X-Real-IP $remote_addr;
# Maintains entire proxy chain information
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# Ensures original Host header reaches backend
proxy_set_header Host $http_host;
# Custom header indicating Nginx proxy
proxy_set_header X-NginX-Proxy true;
proxy_pass http://otherapp/;
proxy_redirect off;
}
X-Real-IP: Without this, your Node.js app would only see Nginx's IP address, breaking IP-based features like rate limiting or geo-location.
X-Forwarded-For: Critical when you have multiple proxy layers. The $proxy_add_x_forwarded_for
variable intelligently appends to existing headers.
Host: Particularly important for virtual hosting. Node.js applications often need the original hostname for URL generation or multi-tenant setups.
Here's an enhanced version with WebSocket support and timeouts:
location / {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Forwarded-Proto $scheme;
# Standard headers
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_pass http://node_backend;
proxy_read_timeout 300s;
proxy_connect_timeout 75s;
}
1. Overriding needed headers: Don't blindly overwrite existing X-Forwarded-For headers
2. Protocol mismatches: Always include X-Forwarded-Proto when using HTTPS
3. WebSocket issues: The Upgrade and Connection headers are essential for WS connections
For microservices architectures, consider adding:
proxy_set_header X-Request-ID $request_id;
proxy_set_header X-Service-Name frontend_gateway;
This enables better distributed tracing in your Node.js applications.