在Nginx HTTPS server块中添加add_header Strict-Transport-Security指令时,必须监听443端口、启用SSL、使用always参数,并避免后端重复注入;includeSubDomains和preload需满足全站HTTPS等前提条件。

直接在 Nginx 的 HTTPS server 块中添加 add_header 指令即可,但必须满足几个关键条件才能真正生效、避免误配或业务中断。
只放在 443 端口的 HTTPS server 块里
HSTS 头浏览器只认 HTTPS 响应,HTTP(80 端口)块里加了也无效,还可能引发误解。务必确认配置位置:
- 监听 443 端口,且已启用
ssl on或配置了有效的证书(ssl_certificate和ssl_certificate_key) - 不要写在
http或location块顶层;也不要在 HTTP server 块中复制粘贴同一行 - 示例正确结构:
listen 443 ssl http2;
server_name example.com;
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# 其他配置...
}
必须带 always 参数
不加 always,Nginx 默认只对 2xx 成功响应添加该头。一旦返回 404、500 或 304,HSTS 就中断传递,策略可能失效或被浏览器丢弃。
-
always保证所有响应(包括错误和缓存验证)都携带 HSTS 头 - 缺少它,灰度期或异常流量下容易出现策略断层
- 语法错误示例:
add_header Strict-Transport-Security "...";→ 缺always,不推荐
注意子域与预加载的约束条件
includeSubDomains 和 preload 不是“开了就更安全”,它们有明确前提:
-
includeSubDomains:要求所有子域名(如api.example.com、blog.example.com)都已支持并部署了 HTTPS,否则这些子域将彻底无法访问 -
preload:需满足三项硬性条件——全站 HTTPS、含子域且全部 HTTPS、max-age ≥ 31536000(1 年),且必须提交到浏览器预加载列表(如 hstspreload.org)才起效 - 上线前建议先用较小
max-age=300(5 分钟)灰度验证,确认无子域访问问题后再逐步延长
反向代理场景:屏蔽后端 HSTS 头
如果 Nginx 后面还有一层应用(如 Spring Boot、Node.js),而它自己也返回 Strict-Transport-Security,就会造成冲突:
- 测试环境走 HTTP 时,后端若返回 HSTS,浏览器会直接拒绝加载页面
- 生产环境可能出现策略覆盖或 max-age 不一致
- 解决方式:在对应
location块中加一行proxy_hide_header Strict-Transport-Security; - 再统一由 Nginx 的
add_header注入,确保策略唯一、可控


















