Nginx生产环境配置HSTS需在443端口server块中添加add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;,配合80端口return 301跳转,并分阶段验证max-age、子域HTTPS支持及preload前提。

在 Linux Nginx 生产环境中配置 HSTS,核心不是加一行头就完事,而是要确保它真正生效、不翻车、不锁死用户——尤其当你的服务已对外提供、有真实流量时。关键在于:HSTS 必须部署在 HTTPS 的 server 块中,配合 80 端口 301 跳转形成闭环,且 max-age、includeSubDomains、preload 这三项必须按基础设施成熟度分阶段启用。
HTTPS server 块中正确注入 HSTS 头
HSTS 只能通过 HTTPS 响应传递,HTTP 响应里设置完全无效。必须放在 listen 443 ssl 的 server 块内,且需带 always 参数:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;-
always是硬性要求:它确保 404、500、304 等非 2xx 响应也携带 HSTS 头,防止攻击者用错误路径绕过策略 - 不能写在
if块或某些 location 内——Nginx 的if是伪指令,add_header在其中会被跳过 - max-age 必须 ≥ 31536000(1 年),否则 Chrome 120+、Firefox 125+ 等现代浏览器直接忽略该头
80 端口必须配 clean 301 跳转
HSTS 解决的是“第二次及以后访问”,首次 HTTP 请求仍可能被劫持。因此必须靠 80 端口跳转堵住入口漏洞:
Linux系统管理专家,覆盖12大模块:用户权限、SSH、存储、网络、systemd、防火墙、日志监控、备份恢复、TLS证书、Ansible、容器、IaC。提供配置、验证、加固、监控、备份、自动化、故障排查、回滚闭环。关键词:useradd、sudo、sshd_config、chmod、SEL...
- 单独建一个
server { listen 80; ... }块,只做一件事:return 301 https://$host$request_uri; - 用
return,不用rewrite:避免多跳、变量解析异常和性能损耗 - 不加任何
ssl_*指令(如ssl_certificate),否则 Nginx 启动报错 -
$host支持多域名,$request_uri完整保留路径与查询参数(#锚点除外)
includeSubDomains 与 preload 的启用前提
这两个参数影响范围极大,误配会导致子域不可访问或预加载失败,上线前必须确认:
-
includeSubDomains:要求所有一级子域(如api.example.com、cdn.example.com)都已部署有效 HTTPS,且证书匹配;否则这些子域将彻底无法打开 -
preload:提交到 hstspreload.org 后不可快速撤回,需满足全部条件:全站 301 到 HTTPS、HSTS max-age ≥ 31536000、包含includeSubDomains、响应头必须带always - 首次上线建议先去掉
preload和includeSubDomains,用max-age=300(5 分钟)测试一周,确认无跳转失败、证书链问题、子域异常后再逐步升级
常见失效原因与验证方法
配置写完 ≠ 生效。以下三点必须逐项检查:
-
语法与权限:运行
sudo nginx -t,确认证书路径存在、Nginx 对privkey.pem有读权限 -
链完整性:HSTS 不生效常因 HTTPS 本身不稳。用
openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -text查证书是否含完整中间链 -
实测响应头:用
curl -I https://example.com,看输出中是否有Strict-Transport-Security行;再用浏览器开发者工具 → Network → Headers 验证值是否匹配

















