Nginx 的 add_header 不继承父块,location 中未显式设置会导致 HSTS 头丢失;必须在每个 location 中完整重写或用 map + always 统一管理。

Nginx 的 add_header 不继承父块,location 中未显式设置就会丢失 HSTS 头 —— 这是常见配置陷阱。
add_header 本身不继承,不是“追加”而是“覆盖当前作用域”
add_header 在每个配置块(server、location)中是独立生效的,不会自动合并上级定义。即使 server 块写了 add_header Strict-Transport-Security "max-age=31536000; includeSubDomains",只要某个 location 块里没再写一遍,该 location 下的响应就**完全不带 HSTS 头**。
- 它不像
set或proxy_set_header那样有隐式继承链 - 每个 location 是一个“全新 header 列表”,只包含本块中写的
add_header指令 - 空 location 或仅含
proxy_pass的 location 最容易漏掉 HSTS
正确覆盖 HSTS:在 location 中重新完整声明
想让某个 location 使用不同 HSTS 策略(比如禁用子域、缩短 max-age),必须在该 location 内**完整重写** add_header Strict-Transport-Security,不能只写一半或依赖继承。
- ✅ 正确(覆盖为不含 includeSubDomains):
location /api/ {
add_header Strict-Transport-Security "max-age=31536000";
proxy_pass http://backend;
} - ❌ 错误(以为只是“补充”,实际会丢失整个头):
location /api/ {
# 缺少 add_header → HSTS 彻底消失
proxy_pass http://backend;
}
避免重复和维护难:用 map + add_header 统一管理
如果多个 location 需要不同 HSTS 策略,硬写多遍易出错。推荐用 map 提前定义值,再在各 location 中引用:
- 在 http 块顶部定义:
map $request_uri $hsts_value {
default "max-age=31536000; includeSubDomains";
~/api/ "max-age=31536000";
~/health "max-age=300";
} - 在 server 块中统一添加:
add_header Strict-Transport-Security $hsts_value always;
(always确保 2xx/3xx/4xx/5xx 响应都带上)
注意 always 参数和响应状态码的关系
默认情况下,add_header 只对 2xx 和 3xx 响应生效。HSTS 必须在所有 HTTPS 响应中发送(包括 404、403),否则浏览器可能不更新策略。务必加 always:
- ✅
add_header Strict-Transport-Security "max-age=31536000" always; - ❌
add_header Strict-Transport-Security "max-age=31536000";(404 时不会发 HSTS)


















