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 或工具更友好。