必须用短周期max-age做灰度测试,因为HSTS一旦下发且max-age过高,用户在有效期内无法回退HTTP访问,子域未HTTPS化时启用includeSubDomains还可能导致主站被浏览器标记为永久不可用。

为什么必须用短周期 max-age 做灰度测试
因为 HSTS 是浏览器强制执行的策略,一旦下发且 max-age 设得过高,用户在有效期内就再也无法通过 HTTP 访问你的站点——哪怕你立刻回滚配置,也无济于事。更危险的是,如果某个子域(比如 api.example.com)还没完成 HTTPS 改造,而你已启用 includeSubDomains,用户访问该子域失败后,主站后续也可能被浏览器标记为“永久不可用”。所以首次上线必须从极小值起步,把风险锁死在可控窗口内。
具体怎么配:5 分钟灰度起步
在 Nginx 的 HTTPS server 块(即 listen 443 ssl 的配置段)中加入以下行:
add_header Strict-Transport-Security "max-age=300; includeSubDomains" always;
注意三点:
-
必须加
always:否则 301/404/500 等非 2xx 响应不会携带该头,策略会断层 -
先不加
preload:预加载是不可逆操作,灰度阶段严禁启用 -
暂不开启
includeSubDomains也可行:若子域尚未全部 HTTPS 就绪,可先去掉这一项,只保护主站
上线后要盯什么
设置好后,不是一劳永逸,而是进入关键观察期。建议至少持续监控 15–30 分钟,并重点确认:
- 主站和所有目标子域(如
www、api、cdn)能否稳定返回 200 + 有效的 HTTPS 页面 - 浏览器开发者工具的 Network 标签页里,每个响应头中是否都正确出现了
Strict-Transport-Security: max-age=300; ... - 有没有混合内容警告(Mixed Content)、证书错误(NET::ERR_CERT_...)或跳转循环(301 → 301)
- 用 curl 验证:
curl -I https://example.com和curl -I https://api.example.com,检查响应头是否一致生效
平滑延长 max-age 的节奏
确认无异常后,按阶梯式延长,每次变更后都留出足够观察时间:
- 第 1 步:从
300(5 分钟)→86400(1 天),观察 24 小时 - 第 2 步:→
2592000(30 天),观察 3–5 天 - 第 3 步:→
31536000(1 年),同时补上preload前,必须确保:全站 HTTPS、所有子域独立可用、每个子域响应头含完整 HSTS、且已通过 hstspreload.org 自检


















