0

Nginx HSTS和HTTPS强制跳转配置:一次搞清楚两个安全机制怎么一起用

2026.05.24 | youres | 15次围观

很多新手在给网站配置HTTPS的时候,会遇到一个问题:HTTP访问到底是做301重定向到HTTPS,还是直接配置HSTS(Strict-Transport-Security)?这两个机制看起来都能把HTTP流量引到HTTPS,它们之间有什么区别?能不能同时配置?本文就来把这件事说清楚。

先搞清楚两个机制的区别

在说配置之前,先弄明白这两个东西到底在干什么。

HTTP强制跳转(也叫HTTPS重定向),是在服务端把HTTP请求301或302跳转到HTTPS。比如访问http://example.com,浏览器收到一个响应头告诉它「去访问https://example.com」,浏览器照做,访问就过去了。整个过程浏览器是知情的——它知道自己被跳了。

HSTS不一样。它是一个响应头,叫Strict-Transport-Security。当浏览器第一次访问一个域名收到这个头之后,浏览器会把这个域名记下来。之后无论用户是敲了http://还是从第三方链接点过来,浏览器自己就自动把请求升级到HTTPS,根本不会发起HTTP请求,更不会走DNS解析后再跳转这一步。整个过程在浏览器本地完成,服务端感知不到第一次之后的HTTP流量。

一个简单对比:

  • 跳转:服务端告诉浏览器该去哪
  • HSTS:浏览器自己记住必须去哪

配置HTTPS强制跳转(Nginx端)

这是最常见的做法,在server块里监听80端口,然后把请求重定向到443。

server {
    listen 80;
    server_name example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name example.com;
    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    root /var/www/html;
    index index.html;
}

这里用的是301(永久重定向),告诉搜索引擎这个跳转是永久的,有助于SEO。第一次访问会慢一点(多一次HTTP往返),但之后浏览器会缓存这个跳转。

配置HSTS(Strict-Transport-Security)

HSTS的配置放在443的server块里,通过add_header指令添加到响应头中。

server {
    listen 443 ssl http2;
    server_name example.com;
    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    # HSTS 基本配置
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
}

参数说明:

  • max-age=31536000:浏览器记住这个规则的时间,单位是秒。31536000秒等于一年。建议不要设置太短,否则意义不大。
  • includeSubDomains:可选,表示子域名也适用这个规则。开启之前确保所有子域名都支持HTTPS。

两个机制能不能同时配置

能,而且对于大多数生产环境来说,推荐两个都配置

原因很简单——它们服务的对象不同:

  • 强制跳转:保护第一次访问的用户(浏览器还没记住HSTS规则的用户)
  • HSTS:保护后续所有访问(浏览器记住之后,完全本地处理,速度更快)

两者配合使用,覆盖了从新用户第一次访问到老用户所有场景。

同时配置时的正确写法

# HTTP 监听块:做第一次跳转
server {
    listen 80;
    server_name example.com;
    return 301 https://$host$request_uri;
}

# HTTPS 监听块
server {
    listen 443 ssl http2;
    server_name example.com;
    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    root /var/www/html;
    index index.html;

    # HSTS 配置
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    # 其他安全头
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
}

常见的坑和注意点

1. 先只配跳转,不急着开HSTS

如果网站刚刚切换到HTTPS,建议先用跳转,观察一段时间确认HTTPS服务完全稳定了,再加HSTS。因为一旦浏览器记住了HSTS规则,即便你把HTTPS撤了,用户在max-age有效期内依然无法通过HTTP访问,对用户体验是灾难性的。

2. HSTS的max-age不要设太小

有些教程会写max-age=0,意思是禁用HSTS。设太小的话等于没配,浏览器记不住,下次访问还是可能走HTTP。生产环境建议至少一年(31536000秒)。

3. includeSubDomains用之前要确认

开启这个参数之前,确保所有子域名都上了HTTPS。比如api.example.comblog.example.com这些。如果有子域名还在用HTTP,那些域名会被强制HTTPS访问,如果证书不匹配或者服务没准备好,反而会出问题。

4. 跳转别忘了带$request_uri

常见的错误写法是:

return 301 https://example.com;

这样跳转之后,用户访问的路径会被丢掉——访问http://example.com/about会跳到https://example.com而不是https://example.com/about。正确写法是带$request_uri变量。

5. 配置文件里的add_header继承问题

Nginx的add_header指令有个继承规则:在server块里定义的响应头,不会自动继承到error_page处理块。如果有自定义错误页,记得单独在error_page块里也加上add_header。

配置完怎么验证

最直接的方式是用curl检查响应头:

# 检查HSTS头是否存在
curl -I https://example.com

# 检查跳转是否生效
curl -I http://example.com

如果HSTS配置正确,会看到Strict-Transport-Security: max-age=31536000; includeSubDomains这样的响应头。HTTP重定向正确的话,访问HTTP URL会返回301/302并带Location指向HTTPS。

也可以用浏览器开发者工具的Network面板查看响应头,或者用Security Headers这类在线工具做全面检测。

总结一下

  • HTTP强制跳转和HSTS是两回事,原理不同,互相补充。
  • 生产环境推荐两个都配置,跳转覆盖首次访问,HSTS保护后续访问。
  • 从HTTP切换到HTTPS时,先上跳转,观察稳定后再加HSTS。
  • max-age设一年以上,includeSubDomains用之前确认子域名全支持HTTPS。

这两个机制配合起来,能把网站HTTPS覆盖率从「部分场景」提升到「全场景」,安全效果远好于单独用跳转。配置本身不复杂,关键是搞清楚它们的适用场景和先后顺序。


相关推荐:

版权声明

本文仅代表个人观点。
本文系AI辅助作者原创,未经许可,转载请保留原文链接。

发表评论