proxy_hide_header仅屏蔽指定响应头且须置于proxy_pass之后,不支持正则或通配符;需配合server_tokens off和proxy_set_header Server ""才能彻底隐藏Server头。

proxy_hide_header 本身不能“精准移除”——它只做屏蔽,不区分来源、不解析内容、不支持正则。所谓“精准”,靠的是明确指定字段名 + 正确作用域 + 配合其他指令协同控制。
proxy_hide_header 必须写在 proxy_pass 之后才生效
这是最常踩的坑:把 proxy_hide_header 放在 proxy_pass 前面,配置完全不生效,响应头照旧透传。
- 正确顺序:
proxy_pass→proxy_hide_header X-Powered-By→proxy_hide_header Server - 它只对当前
location生效;父块(如http)里写的不会自动继承到子location - 每个要隐藏的头必须单独一行,不支持逗号分隔或通配符,例如不能写
proxy_hide_header X-Powered-By Server
哪些后端头该优先屏蔽(按泄露风险排序)
Spring Boot、Express、Laravel、Tomcat 等默认注入的头,是攻击面入口,需逐个明确屏蔽:
-
X-Powered-By:PHP/8.2、Express、Spring Boot 常带,暴露语言和框架版本 -
Server(后端的):如Server: Apache-Coyote/1.1或Server: uvicorn,但注意proxy_hide_header Server不影响 Nginx 自己加的Server头 -
X-Application-Context:Spring Boot 默认返回application:prod,直接暴露环境 -
X-AspNet-Version:.NET 应用特有,泄露 ASP.NET 版本 -
X-Runtime、X-Generator:间接暴露技术选型或 CMS 类型
server_tokens off 和 proxy_set_header Server "" 必须配合使用
单靠 proxy_hide_header Server 很可能失败——因为 Nginx 对 Server 头有特殊处理逻辑,且错误页、重定向响应等场景下容易漏掉。
-
server_tokens off要放在http或server块中,关闭 Nginx 自身输出的版本号(如nginx/1.24.0) -
proxy_set_header Server ""放在location内、proxy_pass后,强制清空该头(比proxy_hide_header更可靠) - 如果想统一显示网关标识,可用
add_header Server "MyAPI-Gateway",但注意它会覆盖所有同名头,包括你刚清空的
验证时 curl -I 看到的 Server 头仍存在?检查这三点
即使配置全对,curl -I 仍看到 Server 字段,大概率是以下原因:
- 后端返回了 502/503 等错误页,这些页面由 Nginx 自己生成,其
Server头不受proxy_hide_header控制,需配合error_page自定义错误页并确保后端关闭调试模式 -
server_tokens off没生效范围:比如写在某个location里,但错误页走的是默认 server 上下文 - 浏览器缓存了旧响应头,或中间 CDN/代理层缓存了带
Server的响应,务必用curl -H "Cache-Control: no-cache" -I绕过缓存直连 Nginx
真正难的不是写几行 proxy_hide_header,而是厘清响应链路上每个环节(后端、Nginx 主动添加、Nginx 错误页、CDN)各自贡献了哪些 Server 或敏感头,并分别设防。漏掉任意一环,就等于没藏住。


















