HSTS是通过HTTPS响应头Strict-Transport-Security告知浏览器“只许用HTTPS访问”,必须在443端口SSL server块中配置add_header指令,配合max-age、includeSubDomains和preload参数,并确保全站HTTPS稳定运行且跳转逻辑先行。

HSTS 不是“开启开关”,而是通过 HTTPS 响应头告诉浏览器:“只许用 HTTPS 访问我”。配置本身只需一行指令,但真正起效的前提是全站 HTTPS 已稳定运行,且不能有遗漏环节。
必须在 HTTPS 的 server 块中添加响应头
HSTS 只能由 HTTPS 响应携带,HTTP 响应里加了也无效,浏览器直接忽略。务必确认你是在监听 443 端口、启用 SSL 的 server 块中操作:
- 添加这行配置:add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
- always 参数很关键——它确保即使返回 404、500 或 304,HSTS 头依然发出,避免策略意外丢失
- 不要把它写在监听 80 端口的 HTTP server 块里,那毫无意义
参数设置要讲逻辑,别直接抄模板
三个核心参数不是摆设,各自承担不同风险边界:
- max-age=31536000 表示 1 年有效期;首次上线建议先设为 300(5 分钟),验证无误后再逐步延长
- includeSubDomains 会让 api.example.com、cdn.example.com 等所有子域也强制 HTTPS;启用前必须确认每个子域都已部署有效证书并可正常 HTTPS 访问
- preload 是高风险动作——意味着你准备提交域名到浏览器预加载列表;一旦加入,无法快速撤回,且要求 max-age ≥ 10886400、强制启用 includeSubDomains 等硬性条件
跳转与 HSTS 要分工明确
HTTP 到 HTTPS 的跳转和 HSTS 是两件事,必须分开处理:
- 在 80 端口的 server 块 中用 return 301 https://$host$request_uri; 完成跳转,不推荐 rewrite
- 确保 $host 来自 server_name 白名单(如 server_name example.com www.example.com;),防止 Host 头注入导致跳转到恶意地址
- HSTS 不负责跳转,它只让浏览器“记住”以后不再发 HTTP 请求;所以跳转逻辑必须先跑通,否则用户第一次访问就会失败
上线前必须验证的几件事
配置完 reload,不代表就安全了。请逐项确认:
- 用 curl -I https://example.com 查看响应头,确认 Strict-Transport-Security 出现在结果中,且值符合预期
- 打开 chrome://net-internals/#hsts,手动查询域名是否已被浏览器缓存(注意:Chrome 对已 HSTS 的域名会直接拦截 HTTP 请求,不发包)
- 若使用 CDN(如 Cloudflare),检查其是否透传 HSTS 头;部分 CDN 默认屏蔽自定义 Header,需在控制台单独开启
- 确认所有页面资源(CSS/JS/图片/iframe)链接均为 HTTPS 或协议相对路径(//),避免混合内容警告导致 HSTS 实际失效


















