nginx中配置hsts需在443端口server块内使用add_header strict-transport-security "max-age=31536000; includesubdomains" always;,禁用http上下文配置,反向代理需屏蔽后端hsts头,max-age与includesubdomains须渐进启用,preload需满足全站https等严苛条件。

在 Nginx 中配置 HSTS 响应头,核心是让浏览器“记住”只用 HTTPS 访问你的域名,从而跳过首次 HTTP 请求这个最易被劫持的环节。它不是跳转指令,而是一把“记忆型安全锁”。配置本身简单,但位置、参数和节奏稍有偏差,就可能导致子域无法访问、测试环境被永久拦截,甚至上线后难以回退。
必须放在 443 端口的 HTTPS server 块里
HSTS 头只在加密连接下生效,浏览器会直接忽略 HTTP(80 端口)响应中的该头。如果错加在 http 块、location 块顶层或 80 端口 server 中,等于没配。
- 只在
server { listen 443 ssl; }块内添加 - 确保该块已正确配置
ssl_certificate和ssl_certificate_key - 禁用全局
http块或非 HTTPS 上下文中的add_header指令
add_header 必须带 always 参数
不加 always,Nginx 默认只在 2xx 响应中发送该头。一旦遇到 404、500、304 等状态,HSTS 就中断传递,策略可能失效或被浏览器丢弃。
- 正确写法:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; - 错误写法:
add_header Strict-Transport-Security "max-age=31536000";(缺 always,不可靠) - 若使用反向代理(如 Spring Boot、Node.js),需屏蔽后端返回的 HSTS 头:
proxy_hide_header Strict-Transport-Security;
max-age 和 includeSubDomains 要量力而行
max-age 决定浏览器强制 HTTPS 的时长;includeSubDomains 把策略扩展到所有一级子域(如 www、api、blog),但这是有代价的。
- 首次部署建议用
max-age=300(5 分钟),观察 15 分钟以上 - 确认无证书错误、混合内容、子域不可达、跳转异常等问题后再逐步延长
- 启用
includeSubDomains前,必须确保每个子域都能通过 HTTPS 正常访问、证书有效;否则用户访问失败后,主站也可能被浏览器标记为“不安全”
preload 是承诺,不是开关
加上 preload 是为了提交到浏览器预加载列表,实现“第一次访问即强制 HTTPS”。但这不是可逆操作,一旦收录,撤回需数月甚至半年以上。
- 必须同时满足:全站 HTTPS、
max-age ≥ 31536000、含includeSubDomains、所有子域响应头中也有完整 HSTS 策略 - 未满足预加载全部条件时提前加
preload,会导致审核被拒或上线后无法修复 - 上线前务必灰度验证,并配套 80 端口 clean 的 301 跳转:
return 301 https://$host$request_uri;











