HSTS头必须在生成对应状态码(302/401/404/500)的location块内用add_header+always显式配置,不可依赖server块兜底或父级继承,且需确保语法正确、版本兼容、无internal redirect覆盖。

直接检查 302、401、404、500 这类响应是否带 Strict-Transport-Security 头——只要没出现,基本就是 always 缺失或作用域错位。
用 curl 快速验证异常状态码下的 HSTS 是否存在
不依赖浏览器缓存或重定向链,手动触发目标状态码并查看响应头:
- 测试 302:在对应 location 中临时加
return 302 https://example.com/;,再执行:curl -I -k https://your-domain.com/some-path
确认响应中是否有Strict-Transport-Security:行 - 测试 404:用不存在的路径(如
/nonexistent),或在 location 内加return 404;,同样用curl -I查看 - 测试 500:可配合
error_page 500 = /50x.html;,并在location = /50x.html块中检查是否配置了带always的 HSTS
确认 add_header 是否落在正确的配置层级
HSTS 头必须出现在实际生成该响应的 location 块内,不能只靠 server 块“兜底”:
- 如果用了
proxy_pass,且后端返回 302,Nginx 不会自动补头——必须在该location里显式写:add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; - 如果用了
try_files $uri @backend或error_page 404 = @notfound,这些是 internal redirect,原 location 的头全部丢弃;@notfound这个 named location 也必须自己配全 HSTS +always - 检查有没有子 location 覆盖了父级配置,例如:
server { add_header Strict-Transport-Security "..."; }location /api { add_header X-Content-Type-Options nosniff; }
此时/api下所有响应(包括 302、404)都不会有 HSTS 头
检查语法和版本兼容性
即使逻辑正确,细节错误也会导致配置不生效:
-
always必须紧贴在引号后的空格之后、分号之前,格式为:add_header Strict-Transport-Security "max-age=31536000" always;
漏掉空格、拼成always;或写成Always都会报错或静默失效 - 确认 Nginx 版本 ≥ 1.7.5(2014 年发布),当前主流版本均满足;可用
nginx -v查看 - 重载配置后,用
nginx -t验证语法,避免因其他错误导致 reload 失败而误以为 HSTS 没生效
区分 external 与 internal 重定向场景
同一行 return 302 在不同上下文行为不同:
-
external redirect(如
return 302 https://...):响应由当前 location 生成,HSTS 头必须在此 location 内声明 +always -
internal redirect(如
rewrite ^/old(.*)$ /new$1 last;或try_files $uri @fallback;):响应由目标 location(如@fallback)生成,源 location 的 HSTS 完全无效,目标块必须独立配置 - 若不确定类型,可在日志中开启
log_format记录$request_completion和$status,观察真实响应来源


















