nginx中配置hsts需严格限定在443端口https server块内,使用add_header strict-transport-security "max-age=31536000; includesubdomains" always;,并确保全站https、证书有效、子域可用,首次部署建议max-age=300灰度验证。

在 Nginx 中配置 HTTP Strict Transport Security(HSTS),核心是让浏览器记住“只用 HTTPS 访问你的域名”,从而跳过首次 HTTP 请求这个最易被劫持的环节。它不是跳转指令,而是一条由服务器发出、浏览器强制遵守的安全承诺。配置本身不难,但位置、参数和上线节奏必须严谨,否则可能造成子域无法访问、测试环境被永久拦截等严重后果。
只在 443 端口的 HTTPS server 块中添加
HSTS 头仅在加密连接下生效,浏览器会直接忽略 HTTP(80 端口)响应中的该头。错加在 http 块、location 块顶层或 80 端口 server 中,等于没配。
- 正确做法:确保只出现在
server { listen 443 ssl; }块内 - 若使用反向代理(如后端是 Spring Boot 或 Node.js),需屏蔽后端返回的 HSTS 头:
proxy_hide_header Strict-Transport-Security; - 禁用 rewrite 跳转,统一用
return 301 https://$host$request_uri;处理 80 端口重定向
add_header 必须带 always 参数
不加 always,Nginx 默认只在 2xx 响应中发送 HSTS 头。一旦遇到 404、500、304 等状态,策略就中断传递,浏览器可能丢弃或拒绝缓存该策略。
- 标准写法:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; -
preload是可选标记,仅在满足全站 HTTPS、含子域、max-age ≥ 31536000等硬性条件,并准备提交至 hstspreload.org 时启用
includeSubDomains 要求所有子域 HTTPS 可用
启用 includeSubDomains 意味着 api.example.com、shop.example.com 等所有一级子域都必须支持 HTTPS,且证书有效、无警告。
- 上线前逐个验证:
curl -I https://sub.example.com,确认返回 200 且无证书错误 - 检查 Nginx 错误日志,搜索
ssl_handshake_failed或no suitable certificate - 若子域尚未全量 HTTPS,先去掉
includeSubDomains,仅对主站生效
分阶段灰度上线,别一上来就设一年
max-age 设太大,出问题后用户端无法快速清除(只能等过期或手动清理浏览器 HSTS 缓存)。生产环境推荐从短周期起步。
- 首次部署建议:
max-age=300(5 分钟) - 观察 15 分钟以上,确认无证书错误、混合内容、子域不可达、跳转异常等问题
- 再逐步延长至 31536000(1 年),为后续启用
preload打基础 - 用
curl -I https://example.com检查响应头是否含预期值,并注意 status 是否为 200
配套基础必须稳固,否则 HSTS 反成障碍。SSL 证书必须有效、受信,且覆盖所有 server_name 声明的域名(包括 www 和裸域);80 端口必须配置 clean 的 301 跳转;HSTS 不是补丁,而是 HTTPS 安全闭环的最后一步。











