Web 服务器

HTTP 强制跳转 HTTPS 配置

作者: · 最后核实

HTTP 跳转 HTTPS 的标准做法,是对每个 http:// 请求返回一次 301 或 308 永久跳转,直接到达对应的 https:// 地址。套了 CDN 时要在 CDN 上跳转或判断 X-Forwarded-Proto,否则会无限跳转。Let's Encrypt 续期不受跳转影响。覆盖 Nginx、Apache 2.4、Caddy 2、IIS 10、宝塔面板,以及阿里云、腾讯云、Cloudflare 等 CDN。

前提条件

强制 HTTPS 之前,HTTPS 本身必须已经正常。

  • 已安装有效证书,https://example.com 打开没有任何警告(用 SSL 证书检查 确认)。
  • 能修改 Web 服务器或 CDN 的配置。
  • 页面里没有写死的 http:// 资源,可以用 混合内容扫描 查找。

第一步:Nginx

Nginx 用一个只做跳转的 80 端口 server 块,把请求 301 到同名的 HTTPS 地址:

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

写固定域名可以一次把 www 和主域名统一;想保留访问的域名就写 https://$host$request_uri。然后执行 sudo nginx -t && sudo systemctl reload nginx。

第二步:Apache

Apache 在 80 端口的虚拟主机里用 Redirect permanent 跳转:

<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    Redirect permanent / https://example.com/
</VirtualHost>

只能用 .htaccess(虚拟主机)时用 mod_rewrite:

RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

第三步:Caddy、IIS 和宝塔

Caddy 对所有写了域名的站点自动做 HTTP 跳转,不需要配置。宝塔在网站 → 设置 → SSL 里打开“强制 HTTPS”。IIS 先安装 URL Rewrite 模块,在 web.config 里加规则:

<rule name="HTTP to HTTPS" stopProcessing="true">
  <match url="(.*)" />
  <conditions>
    <add input="{HTTPS}" pattern="^OFF$" />
  </conditions>
  <action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="Permanent" />
</rule>

第四步:套了 CDN 或负载均衡时

CDN 以 HTTP 回源时,源站看到的每个请求都是 HTTP,源站再跳转就会死循环。两种做法:在 CDN 上开启强制跳转(阿里云、腾讯云 CDN 的“强制跳转”,Cloudflare 的 Always Use HTTPS)并去掉源站的跳转;或者只在代理告诉你客户端用的是 HTTP 时才跳转:

if ($http_x_forwarded_proto = "http") {
    return 301 https://$host$request_uri;
}

更好的做法是让 CDN 用 HTTPS 回源并校验证书。阿里云 CDN 的设置见 阿里云 CDN 配置 HTTPS。

验证

配置正确时,每个 http:// 入口只跳转一次,直接到达最终的 https:// 地址。用 curl 逐个检查入口:

curl -sI http://example.com | grep -iE '^(HTTP|location)'
curl -sI http://www.example.com | grep -iE '^(HTTP|location)'
curl -sIL http://www.example.com | grep -iE '^(HTTP|location)'

再用 SSL 证书检查 检查 HTTPS 本身,或在终端运行:

curl ssl.sh/example.com

自动续期

跳转不影响 Let's Encrypt 续期:HTTP-01 验证会跟随最多 10 次跳转(只限 80/443 端口的 http/https),而且不校验 HTTPS 目标的证书,即使证书已过期也不影响续期。会破坏 HTTP-01 的是跳到另一个不提供验证文件的域名或端口,或者删掉了 80 端口的监听。保留 80 端口的 server 块,让 ACME 客户端照常续期(见 证书自动续期)。跳转正常后,再加上 HSTS。

常见问题排查

  • ERR_TOO_MANY_REDIRECTS(重定向次数过多):CDN 已经用 HTTPS 接收请求,源站又按 HTTP 跳转,见第四步;宝塔“强制 HTTPS”和 CDN 跳转同时开也可能出现。
  • 切换后提示混合内容:页面还在加载 http:// 的脚本或图片,见 混合内容警告。
  • 跳转后浏览器提示证书错误:证书不包含跳转目标域名,见 您的连接不是私密连接。
  • 表单或 API 出错:301 把 POST 变成了 GET,API 改用 308。
  • 加跳转后续期失败:跳到了别的域名或端口,见 certbot 连接超时。

常见问题

只做跳转就算全站 HTTPS 了吗?

还不够。第一次 HTTP 请求仍然是明文,在跳转之前就可能被劫持(国内常见的运营商插广告就发生在这一步)。再加上 HSTS,浏览器以后会直接访问 HTTPS,见 开启 HSTS。

宝塔面板怎么开强制 HTTPS?

网站 → 设置 → SSL,部署证书后打开“强制 HTTPS”开关,宝塔会在站点配置里加上跳转规则。不要再手动加一遍,否则可能重复跳转。详见 宝塔面板配置 SSL 证书。

跳转需要排除 /.well-known/acme-challenge/ 吗?

对 Let's Encrypt 不需要,它会跟随跳转。排除掉也没有坏处,对不跟随跳转的其他 CA 或工具更友好。

资料来源

  1. nginx: Configuring HTTPS servers
  2. Apache httpd: SSL/TLS Strong Encryption How-To
  3. Caddy: Automatic HTTPS
  4. Microsoft Learn: Using the URL Rewrite Module
  5. 阿里云 CDN:如何在 CDN 上配置 SSL 证书实现 HTTPS 访问
  6. Let's Encrypt: Challenge Types