排查多节点Nginx HSTS不一致,需验证各节点响应头是否完全相同、稳定生效且无条件透传;重点比对Strict-Transport-Security是否存在、max-age值是否统一、includeSubDomains与preload是否一致;确认HSTS在HTTPS server块中全局配置并带always参数;检查代理链路是否透传或被proxy_hide_header剥离;排除浏览器HSTS缓存及预加载列表干扰。

排查 HSTS 配置在多节点 Nginx 间不一致,核心是确认 Strict-Transport-Security 响应头是否在所有节点上**完全相同、稳定生效、无条件透传**。用户“时有时无”,说明部分请求命中了未配置或错误配置 HSTS 的节点,导致浏览器未收到该头,或收到过期/冲突策略。
检查各节点 HSTS 响应头是否真实存在且一致
不能只看配置文件,必须验证实际响应:
- 从不同客户端(或用 curl 指定不同 Nginx 节点 IP)分别请求同一域名:
curl -I -k https://your-domain.com | grep -i strict - 重点比对三项:是否返回
Strict-Transport-Security;max-age值是否完全相同(如都是31536000);是否都含includeSubDomains和preload(若启用) - 若某节点返回空、值不同、或仅在特定 location 出现(如只在
/api下设置),就直接定位到该节点配置偏差
确认 HSTS 设置位置是否统一且无覆盖
HSTS 头必须在 HTTPS server 块中全局、无条件设置,避免被子配置覆盖:
- 所有节点的
server { listen 443 ssl; ... }块内,应统一使用:add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; - 禁用
add_header在 location 级别重复设置——它会覆盖上级,且always参数缺失会导致 301/302 响应不带 HSTS - 检查是否有
if ($scheme != "https") { ... }类逻辑干扰,或 error_page 重定向路径绕过了 HSTS 设置块
验证代理链路是否透传或污染 HSTS
若前端还有 CDN、WAF 或另一层 Nginx(如 Nginx Proxy Manager),HSTS 可能被中间层清除或改写:
- 在最外层入口(如用户直连的 VIP 或 CDN 回源地址)抓包或 curl,确认 HSTS 头是否从这里开始就缺失
- 检查上游代理是否设置了
proxy_hide_header Strict-Transport-Security—— 这是常见误配,会主动剥离该头 - 若使用 Nginx Proxy Manager(NPM),进入对应 Proxy Host → SSL → 自定义 Headers,确认未禁用或覆盖 HSTS
排查浏览器缓存与 preload 列表干扰
“时有时无”也可能是客户端侧状态残留:
- HSTS 一旦生效,浏览器会强制 HTTPS 并忽略后续 HTTP 响应中的 HSTS 头;可清空浏览器 HSTS 缓存测试(Chrome 访问
chrome://net-internals/#hsts,删除域名) - 若已提交至 HSTS Preload List,该策略将硬编码进浏览器,无法被服务端撤销;此时需确保所有节点长期、稳定提供有效 HSTS,否则会出现“预加载生效但某节点不响应”的错觉
- 用新无痕窗口 + 不同节点 IP 直连,排除本地缓存影响


















