nginx 中严格 hsts 时效需稳、验、退:先设 max-age=300 观察,再逐步升至 86400 和 31536000;必须配 always 参数确保所有响应含 hsts 头;preload 仅在全站 https 稳定且满足条件后启用。

在 Nginx 中设置严格的 HSTS 时效,核心不是单纯拉长 max-age,而是让时效“稳得住、可验证、能回退”。直接设成 1 年(31536000 秒)看似严格,但若基础不牢,反而会锁死访问、引发大面积故障。
时效必须匹配 HTTPS 稳定性
HSTS 的 max-age 值本质是浏览器的信任周期。它只在你已稳定提供 HTTPS 的前提下才有意义:
- 全站所有路径(含 API、静态资源、管理后台)必须能通过 HTTPS 正常响应,无混合内容警告
- 所有 server_name 声明的域名(包括 www、api、admin 等)都需有有效且未过期的证书
- 80 端口必须配置 return 301 跳转,且跳转目标 URL 与实际 HTTPS 域名完全一致(避免 $http_host 注入)
分阶段调高时效,避免“一步到位”风险
首次启用 HSTS 时,严禁直接使用 31536000。应按验证节奏逐步延长:
- 先用 max-age=300(5 分钟)上线,观察日志和用户反馈是否出现子域不可达、证书错误等异常
- 确认 24 小时内无问题后,升至 max-age=86400(1 天),覆盖常见缓存周期
- 稳定运行 3–7 天,再设为 max-age=31536000(1 年),满足等保三级及 PCI DSS 合规要求
always 参数决定时效是否真正“落地”
没有 always,HSTS 时效就不可靠。Nginx 默认只对 2xx/3xx 响应添加 header,而 404、500、304 等状态码缺失 HSTS 头,会导致浏览器中断策略记忆,使 max-age 实际失效:
- 错误写法:add_header Strict-Transport-Security "max-age=31536000; includeSubDomains"
- 正确写法:add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always
preload 不是时效增强,而是时效“固化”
加上 preload 意味着向浏览器厂商提交长期承诺。一旦收录进预加载列表,即使你把 max-age 改成 0,浏览器仍会在数月内强制 HTTPS:
- 仅当满足全部条件才启用:max-age ≥ 31536000、includeSubDomains 已开启、所有子域 HTTPS 可用、全站无 HTTP 回退入口
- 提交前务必访问 hstspreload.org 自检,确认格式与覆盖范围无误
- 灰度期间禁用 preload,待生产环境连续稳定运行至少 2 周后再申请











