启用 includeSubDomains 前必须确保主站及所有子域名均支持 HTTPS、证书有效、策略一致,且 HSTS 头仅在 443 端口 SSL server 块中配置;需逐个验证子域 HTTPS 就绪,避免双头冲突,并建议灰度上线:先 max-age=300,稳定后再设为 31536000 并考虑 preload。

要在 Nginx 中通过 HSTS 的 includeSubDomains 真正覆盖子域名,关键不是加参数,而是确保主站和所有子域名都满足 HTTPS 可用性、证书有效性、策略一致性三个硬条件。否则启用后反而会导致子域名无法访问。
必须在 HTTPS server 块中配置
只允许出现在监听 443 端口、启用了 SSL 的 server 块里:
- 不能写在 HTTP(80 端口)server 块中——浏览器直接忽略
- 不能写在 http 或 location 全局块里——容易被覆盖或误生效
- 正确位置示例:
server {
listen 443 ssl http2;
server_name example.com www.example.com;
ssl_certificate ...;
ssl_certificate_key ...;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
}
启用前必须验证所有子域名 HTTPS 就绪
includeSubDomains 不是“声明即生效”,而是“声明即强制”。一旦浏览器收到该头,后续访问任何子域名(如 api.example.com、blog.example.com)都会跳过 HTTP 尝试,直连 HTTPS。所以:
- 逐个执行
curl -I https://api.example.com,确认返回 200 且无证书告警 - 检查 Nginx 错误日志,搜索
ssl_handshake_failed或no suitable certificate - 子域名的 server 块也必须监听 443、配好证书,并返回相同的 HSTS 头(含 includeSubDomains)
- 若某个子域暂未上 HTTPS(如 test.example.com),必须先下线或重定向,否则用户首次访问就会失败
避免策略冲突:清理后端透传的 HSTS 头
如果后端应用(如 Spring Boot、Node.js)自己设置了 HSTS,而 Nginx 没做拦截,会出现双头或值不一致,导致浏览器拒绝执行策略:
- 在 server 块开头加:
proxy_hide_header Strict-Transport-Security; - 确保只有 Nginx 统一输出 HSTS,且始终带
always参数(保证 404/500 等错误响应也携带) - 用
curl -I https://example.com检查响应头,确认 Strict-Transport-Security 只出现一次、内容准确
灰度上线建议:从低 max-age 开始
生产环境不要一步到位设成 1 年。推荐分两步走:
- 第一阶段:设为
max-age=300(5 分钟),观察 15–30 分钟,确认无跳转异常、混合内容警告、子域名加载失败 - 第二阶段:确认稳定后,再改为
max-age=31536000,并同步开启preload(如需提交预加载列表) - 注意:一旦加入 preload 列表,撤回需数月,且期间所有子域必须持续可用











