最有效方式是在HTTPS server块中配置HSTS头,仅限443端口且启用SSL的server块,必须加always参数确保异常响应也生效,启用includeSubDomains前需全覆盖验证子域HTTPS支持,上线应灰度渐进,避免一步启用preload。

直接在 HTTPS 的 server 块中用 add_header Strict-Transport-Security 配置,是统一管控全站 HTTPS 强制策略最有效的方式。关键不在“加不加”,而在于加在哪、怎么加、加完怎么验证。
必须只在 HTTPS server 块中配置
HSTS 头只有通过加密连接(HTTPS)下发,浏览器才会接受并缓存。如果误写在 HTTP(80 端口)的 server 块里,浏览器会直接忽略,不仅无效,还可能暴露配置意图。
- 只在监听 443 端口、启用 SSL 的
server块内添加,例如:listen 443 ssl http2; - 确保该块已正确配置证书(
ssl_certificate和ssl_certificate_key) - 不要在 HTTP server 或 location 中重复添加——既冗余,又易引发覆盖或遗漏
用 always 参数保障策略不中断
默认情况下,Nginx 只对 2xx/3xx 响应添加 add_header,但错误页(如 404、502)、重定向(304)、网关超时等场景同样需要传递 HSTS 策略,否则用户可能在异常状态下“掉出”安全通道。
- 务必加上
always参数:add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; - 没有
always,遇到后端返回 500 或 CDN 返回 304 时,HSTS 头就消失了 - 反向代理场景下,还需确认后端未用相同 header 覆盖——可在日志中检查响应头实际输出
includeSubDomains 启用前必须全覆盖验证
开启 includeSubDomains 不是“多加几个字”,而是把整个子域生态纳入强制 HTTPS 范围。一旦启用,浏览器会拒绝加载任何未配 HTTPS 的子域名(如 blog.example.com 或 test.example.com),且无提示、不可绕过。
- 逐个执行:
curl -I https://sub.example.com,确认全部返回 200 且证书有效 - 特别注意:CDN 回源域名、监控探针地址、内部测试子域也需支持 HTTPS
- 若暂无法全覆盖,可先去掉
includeSubDomains,仅保护主站,后续再逐步扩展
上线节奏要可控,别一步到位
HSTS 是“单向开关”——尤其启用 preload 后,撤回需数月周期。生产环境切忌首次就设 1 年 + preload。
- 灰度阶段建议:
max-age=300(5 分钟),观察 15 分钟内所有子域访问是否正常 - 确认无混合内容、无证书告警、无跳转循环后,逐步提升为
3600(1 小时)、86400(1 天) - 稳定运行至少 7 天且日志无异常后,再设为
31536000并提交至 hstspreload.org










