HSTS头在错误响应中生效的关键是使用add_header ... always;因Nginx默认仅对2xx/3xx响应添加自定义头,缺always会导致4xx/5xx响应丢失HSTS,使浏览器无法建立HTTPS记忆。

要让 HSTS 头在负载均衡返回错误响应(如 404、500)时依然生效,关键不是“透传”,而是确保 add_header ... always 在 Nginx 配置中被正确使用——因为默认情况下,Nginx 只对 2xx 和 3xx 响应添加自定义头,4xx/5xx 响应会被跳过。
为什么 error 响应里 HSTS 会丢失?
Nginx 的 add_header 指令默认只作用于成功响应(HTTP 状态码 200–399)。当后端服务异常、超时或返回 502/503/504 等错误时,Nginx 作为反向代理生成的错误页不触发该指令,HSTS 头自然不会出现。浏览器收不到这个头,就无法建立强制 HTTPS 的记忆,安全链条就此中断。
必须加 always 参数
在 server 或 location 块中配置 HSTS 时,必须显式加上 always,否则所有非 2xx/3xx 响应都不带 HSTS:
- ✅ 正确写法:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; - ❌ 错误写法:
add_header Strict-Transport-Security "max-age=31536000;"(缺always,500 响应里就没有 HSTS)
确保 HSTS 出现在所有可能出口位置
如果用了多层代理(例如:用户 → CLB/Tengine → Nginx Ingress → 后端),HSTS 必须在最外层能控制响应头的位置设置,且每个环节都要加 always:
- 若用 Tengine/Nginx 做 SSL 终止,在
server { listen 443 ssl; ... }块顶部直接加add_header ... always - 若用 HAProxy 做 TLS 卸载,它本身不支持
add_header always;需在其http-response set-header中启用on-error选项,或改由后端 Nginx 统一注入 - 若用 Ingress-nginx,需在
nginx.ingress.kubernetes.io/configuration-snippet注解中写入含always的指令(注意版本兼容性)
验证是否真正生效
别只测首页 200,务必主动触发错误再检查响应头:
- 访问一个不存在路径(如
/nonexistent),看 Network 面板 Response Headers 是否含Strict-Transport-Security - 模拟后端宕机:临时关闭 upstream,触发 502,确认响应中仍有 HSTS 头
- 用
curl -I https://yoursite.com/nonexistent直接查看 header 输出










