HSTS必须按域名单独配置,不能跨域名共享或全局继承;每个HTTPS server块需显式添加add_header Strict-Transport-Security,且仅在443端口生效,includeSubDomains仅作用于本server_name声明的主域及其子域。

HSTS 本身不支持“跨域名共享策略”,每个域名必须独立声明自己的 Strict-Transport-Security 响应头。当多个域名共用同一个 Nginx 网关(例如统一入口、统一 TLS 终止)时,不能靠一个配置覆盖所有域名——必须为每个 server_name 显式设置 HSTS 头,否则子域名或不同主域之间会出现策略缺失、覆盖或冲突。
多域名场景下 HSTS 必须按域名单独配置
即使多个域名指向同一组后端服务、复用同一份 Nginx 配置结构,HSTS 仍需在每个 HTTPS server 块中单独添加 add_header 指令。原因如下:
- HSTS 策略绑定的是响应头中的 Host 域名,浏览器按域名维度存储和执行策略
- includeSubDomains 只作用于当前 server_name 声明的主域及其子域,对其他主域(如 example.com 和 api.org)完全无效
- 若只在某个 server 块里写 HSTS,其他域名的 HTTPS 响应将不带该头,等同于未启用
推荐做法:用 include 抽离通用安全头,但 HSTS 单独注入
可将大部分安全头(如 X-Content-Type-Options、X-Frame-Options、Referrer-Policy)统一放入 common.conf,但 HSTS 不宜放进去——因为它的 max-age、preload 等参数常因域名安全等级或上线阶段而异。正确方式是:
- 保留 common.conf 存放通用代理头、日志、超时等非域名敏感配置
- 每个域名的 .conf 文件中,在 include common.conf 后,显式添加专属 HSTS 行
- 例如:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
避免常见错误配置
以下做法在多域名网关中容易引发问题:
- 在 http 块顶层或 upstream 块中加 add_header —— Nginx 不允许,且无效
- 仅在 HTTP server 块(listen 80)中设置 HSTS —— 浏览器忽略,必须出现在 HTTPS 响应中
- 对 www.example.com 启用 preload,但 example.com 未配置或配置不一致 —— 导致预加载审核失败,甚至被拒绝收录
- 多个 server 块共用同一份证书但混用 server_name,例如同时写 example.com 和 api.example.com 在一个块里 —— includeSubDomains 虽生效,但无法覆盖跨主域场景(如 example.com 和 other.com)
灰度与验证建议
上线前务必分步验证,尤其涉及 preload 时:
- 先对单个域名启用 max-age=300(5 分钟),用 curl -I https://domain.com 观察响应头是否出现 HSTS
- 确认浏览器访问该域名后,地址栏是否自动跳转 HTTPS,且开发者工具 Security 标签页显示 “HSTS enabled”
- 使用 hstspreload.org 提交前,确保所有目标域名(含 www、api、auth 等)均已部署相同策略,且返回 200 状态码
- 若网关前端有 CDN,确认 CDN 未缓存或剥离 HSTS 响应头(建议在 CDN 上透传 Strict-Transport-Security)











