关键是在 server 或 location 块内配置安全头并显式添加 always 参数,确保 302、404、500 等所有状态码响应均透传 hsts、cors 等安全头,避免因作用域错误、漏写 always 或同名头覆盖导致安全防护失效。

在 Nginx 配置中正确注入安全响应头,关键不是“写在哪”,而是“写对位置 + 带 always + 避免覆盖”。错一层作用域、漏一个 always,302 重定向或 404 页面就可能裸奔。
必须放在 server 或 location 块内,不能丢进 http 全局块
add_header 只在它直接所属的 server 或 location 块中生效,不会从 http 块继承。把安全头写在 http { } 最外层,等于没写——所有站点都收不到。
- ✅ 正确:HTTPS 站点的 443 server 块 内配置(HSTS 必须在此)
- ✅ 正确:特定 API 路径的 location /api { } 内配置(如 CORS)
- ❌ 错误:写在 http { } 里,期望全站自动生效
- ❌ 错误:写在 listen 80 的 HTTP server 块里配 HSTS(浏览器直接忽略)
every add_header 都要带 always 参数
默认情况下,Nginx 只在部分状态码(如 200、301、304)响应中添加 header,而 302、404、500、403 等常见响应会被跳过。这意味着用户访问一个不存在的页面,HSTS 就断一次;API 返回 500,CORS 头就消失——跨域请求直接失败。
- ✅
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; - ✅
add_header Access-Control-Allow-Origin "*" always; - ✅
add_header X-Content-Type-Options "nosniff" always; - ❌ 不加 always → 302 和 500 响应里这些头全都不见
子 location 会完全覆盖父级,不继承也不叠加
只要你在某个 location 块里写了任意一条 add_header,它就会丢弃上级 server 或其他 location 中同名的头,哪怕只写了一条,其余安全头也全部失效。
- ❌ 错误示例:
server { add_header X-Frame-Options "DENY";<br> location /api { add_header X-API-Version "v1"; proxy_pass ...; } }
→ /api 响应里没有 X-Frame-Options - ✅ 正确做法:每个需要安全头的 location,都显式重写全部必需头
location /api {<br> add_header X-Frame-Options "DENY" always;<br> add_header X-Content-Type-Options "nosniff" always;<br> add_header Access-Control-Allow-Origin "*" always;<br> proxy_pass ...;<br> }
按站点实际策略差异化配置,别套模板
同一套 CSP 或 HSTS 配置不能通吃所有域名。主站启用 includeSubDomains,子站若还没 HTTPS,就会被锁死;CSP 若没放行 CDN 字体或第三方 iframe,页面直接白屏。
- HSTS:只在已部署有效证书的 443 server 块 中启用,preload 前必须全链路验证
- CSP:用
map指令按$host区分策略,或先用Content-Security-Policy-Report-Only观察两周 - CORS:前端带凭据时,
Access-Control-Allow-Origin不能为*,需动态设为$http_origin并加always











