Nginx add_header vs proxy_hide_header explained
Direct Answer: Execution Context & Header Flow
- Execution Phase:
add_headerexecutes during the output filter phase, appending directives to the final downstream response sent to the client.proxy_hide_headerexecutes during the upstream response parsing phase, intercepting and removing specific headers from the backend response before Nginx processes them further. - Inheritance Rule:
add_headerdoes not cascade. Defining it in alocationblock immediately overrides all parent-leveladd_headerdirectives unless explicitly redeclared.proxy_hide_headerapplies strictly to the proxy context where declared. For architectural context on how Nginx sits between clients and upstream services, see Server & Platform Implementation Guides. - Security Implication: Stripping upstream headers prevents information leakage (framework versions, internal routing IPs). Injecting headers enforces client-side security policies (CSP, HSTS, X-Frame-Options).
Exact Configuration & Diagnostic Commands
alwaysFlag Requirement: Withoutalways,add_headeronly applies to200, 201, 204, 206, 301, 302, 303, 304, 307, 308responses. Error pages (4xx/5xx) will silently drop security headers. Always appendalways.- Baseline Standards: For validated header values and compliance matrices, reference Nginx Security Headers Configuration.
- Diagnostic Command:
curl -sI -X GET https://target-domain.com/api/v1 | grep -iE '(strict|content-security|x-frame|x-content-type|server|x-powered)'
- Log Inspection Command:
tail -f /var/log/nginx/access.log | grep -E 'upstream_response_time'
Combine with a custom log_format using $upstream_http_x_powered_by to verify upstream header stripping at the log level.
server {
listen 443 ssl;
server_name app.yourdomain.com;
# Strip upstream metadata before response generation
proxy_hide_header X-Powered-By;
proxy_hide_header Server;
proxy_hide_header X-AspNet-Version;
proxy_hide_header X-AspNetMvc-Version;
location / {
proxy_pass http://backend_upstream;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# Inject hardened security headers (always flag covers 4xx/5xx)
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
}
}
Verification & Testing Pipeline
- Baseline Check: Run
curl -I https://target-domain.com/endpoint. Confirm stripped headers are absent and injected headers are present. - Inheritance Override Test: Add a nested
location /static/block containing a singleadd_header. Request/static/asset.cssand verify that parent security headers disappear from the response. - Scope Validation: Execute
nginx -T | grep -E '(add_header|proxy_hide_header)'to audit compiled configuration scope and detect accidental overrides. - Error Response Validation: Temporarily stop the upstream service to trigger
502/504errors. Verify thealwaysflag preserves injected security headers on error responses.
Edge Cases, Conflicts & Rollback Procedures
- FastCGI/SCGI Mismatch:
proxy_hide_headerfails silently for PHP-FPM or similar backends. Usefastcgi_hide_headeroruwsgi_hide_headerrespectively. - Duplicate Header Concatenation: Multiple
add_headerdirectives for the same key generate multiple header lines. Browsers may reject or misinterpret duplicates. Consolidate directives or usemapblocks for conditional injection. - Proxy Buffering Conflict: When
proxy_buffering on;is active,proxy_hide_headerstill applies, but custom upstream header variables ($upstream_http_*) may not populate in logs until buffering completes. - Rollback Procedure: Comment out target directives, run
nginx -t, executenginx -s reload, and re-runcurl -Ito confirm baseline upstream headers return. - Security & Performance Implications: Aggressive stripping of
Cache-ControlorVarybreaks CDN edge caching. Aggressive injection ofContent-Security-Policywithout matching upstream asset paths will block inline scripts/styles and break application functionality.