如何使用 .htaccess 强制启用 HTTPS
使用 .htaccess 的 Apache 重写规则强制 HTTPS,修复 CDN 或负载均衡后的重定向循环,并设置 www 和 HSTS。
要在 Apache 中对所有流量强制启用 HTTPS,需在站点根目录的 .htaccess 文件中添加三行代码:RewriteEngine On、RewriteCond %{HTTPS} off 以及 RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]。
如果你曾经从论坛帖子中复制粘贴过重定向规则,然后眼睁睁看着浏览器不断跳转直至放弃,那么问题很可能并不出在规则本身。通常导致失败的,是位于你服务器前端的那一层代理。
这条规则会拦截所有通过普通 HTTP 到达的请求,并向相同 URL 的 HTTPS 版本发出永久重定向。它适用于已启用 mod_rewrite 且已安装 SSL 证书的 Apache 环境,同时也会在 CDN 或负载均衡器位于源站前端时以特定的、可预测的方式失效。本指南将首先提供可直接复制粘贴的规则,然后介绍针对域名、文件夹和 www 的变体写法,接着说明如何修复重定向循环问题,最后讲解在非 Apache 环境下的处理方案。
核心要点
- 标准规则通过测试
RewriteCond %{HTTPS} off并将请求重写至https://%{HTTP_HOST}%{REQUEST_URI},从而保留访问者请求的确切域名和路径,而不是硬编码单一域名。 R=301发出永久重定向,L停止后续重写处理;在测试阶段,建议先使用R(临时 302 重定向),因为浏览器会积极缓存 301 重定向,一旦配置错误将难以撤销;确认重定向正常后再切换为R=301。- 强制启用 HTTPS 的前提是域名上已安装有效的 TLS/SSL 证书。在没有证书的情况下进行重定向,不会让网站变得更安全,反而会使其完全无法访问。
- 在 TLS 终止代理后端,
%{HTTPS}永远不会为on,因此规则会导致ERR_TOO_MANY_REDIRECTS循环;此时应改为测试%{HTTP:X-Forwarded-Proto}。 - Cloudflare Flexible SSL 循环是 Cloudflare 侧的配置问题,需通过更改加密模式来解决,而非修改
.htaccess。
开始前的准备:SSL 证书与 mod_rewrite
强制启用 HTTPS 的前提是域名上已安装有效的 TLS/SSL 证书。在没有证书的情况下重定向到 HTTPS,并不能保障网站安全,而是会让网站在浏览器安全警告后变得完全无法访问。(“SSL 证书”是行业通用术语,实际使用的协议是 TLS。)在修改 .htaccess 之前,请先在浏览器中直接访问 https://yourdomain.com,并确认地址栏显示安全锁标志,以验证证书已正常生效。
以下规则依赖 Apache 的 mod_rewrite 模块,该模块在大多数共享主机和 cPanel 主机环境中默认启用。.htaccess 文件位于站点根目录,通常是 public_html 或该域名的文档根目录。你可以通过 cPanel 文件管理器(需启用”显示隐藏文件”以查看点文件)、FTP 或 SSH 来编辑该文件。编辑前请务必备份,以便在规则出错时能够快速恢复。
Discover how at OpenReplay.com.
强制所有流量使用 HTTPS 的 .htaccess 规则
将以下内容粘贴到站点根目录的 .htaccess 文件中,即可将所有 HTTP 请求重定向至 HTTPS:
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
逐行解析:RewriteEngine On 开启重写引擎;RewriteCond %{HTTPS} off 仅在连接未加密时触发规则;RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} 将 URL 重建为 HTTPS 版本,其中 %{HTTP_HOST} 和 %{REQUEST_URI} 变量会保留访问者请求的确切域名和路径,因此该规则可跨多个域名使用,且不会静默地强制添加 www。
在标志位 [L,R=301] 中,R=301 发出永久重定向,L 在该规则处停止重写处理。测试阶段建议先单独使用 R(即临时 302 重定向),因为浏览器会强力缓存 301 重定向,一旦配置错误将非常难以撤销;只有在确认重定向正常解析后,再切换为 R=301。
不要重复添加 RewriteEngine On。 如果该行已存在于文件中,只需在其下方添加 RewriteCond 和 RewriteRule 即可。
变体写法:指定域名、子目录及 www 规范化
若多个域名指向同一文档根目录,而你只需对其中一个域名强制启用 HTTPS,可在 HTTP_HOST 上添加条件判断:
RewriteEngine On
RewriteCond %{HTTP_HOST} ^yourdomain\.com [NC]
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
NC 标志使主机名匹配不区分大小写。若需同时实现 HTTPS 强制跳转与 www/非 www 的规范化,htaccessbook 提供了将两种重定向封装在 mod_rewrite 守卫块中的写法:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule (.*) https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</IfModule>
该代码块的原始版本假设 RewriteEngine On 已在文件中更早的位置出现,因此上方示例中已将其补充进来,使代码片段可独立运行。第一条规则将请求切换至 HTTPS;第二条规则为缺少 www 的主机名添加 www 前缀。需要注意的是,[L] 会在规则匹配时立即停止处理,因此一个既没有 www 又使用 HTTP 的请求会经历两次重定向,而非一次:先跳转至 HTTPS,再跳转至带 www 的主机。将规则封装在 <IfModule mod_rewrite.c> 中,可在 mod_rewrite 未加载时让网站以 HTTP 方式继续提供服务(失败开放),而不是抛出 500 错误。
当你在同一个文件中同时处理 HTTPS 强制跳转、www 规范化、若干重定向规则和缓存配置时,手动堆叠这些规则会变得相当繁琐——一个标志位写错或规则顺序颠倒,就可能在生产环境中引发问题。OpenReplay 的 htaccess 生成器可让你通过一组开关来自动生成配置文件:强制 HTTPS、添加或去除 www、设置 301 或 302 重定向、开启 gzip 和浏览器缓存、封锁 IP、配置自定义错误页面等。生成的输出带有注释,随选项变更实时更新,且完全在浏览器中运行,你可以直接复制或下载后与现有配置进行对比。
修复 CDN 或负载均衡器后端的 ERR_TOO_MANY_REDIRECTS
如果你的重定向导致 ERR_TOO_MANY_REDIRECTS,说明浏览器跟随了过多跳转后放弃了,通常原因是 TLS 终止代理或负载均衡器的存在。TLS 在代理层终止,因此源站的 %{HTTPS} 永远不会为 on,规则对每个请求都会触发,重定向循环永远无法终止。解决方案是改为信任转发的协议头:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</IfModule>
此处 RewriteCond %{HTTP:X-Forwarded-Proto} !https 读取代理设置的 X-Forwarded-Proto 请求头,因此规则仅在访问者的原始连接为 HTTP 时才会触发。在提升为 R=301 之前,请先使用 R 进行测试。
Cloudflare Flexible SSL 循环是另一个问题,有其专属的解决方案。在 Flexible 加密模式下,Cloudflare 与你的服务器之间的通信是未加密的,因此源站上坚持要求 HTTPS 的规则会不断将请求循环发送回来。Cloudflare 提供了两种解决途径:在源站移除 HTTPS 重定向,或将加密模式升级为 Full 或更严格的级别(这需要在源站安装证书)。这两种更改均在 Cloudflare 控制台中完成,而非修改 .htaccess。在 Flexible 模式下,访问者仍然通过 HTTPS 浏览,且 Cloudflare 在 X-Forwarded-Proto 中报告的协议反映的是访问者自身的连接协议,因此上述请求头测试在此场景下不会误触发。不过,修正加密模式才是真正的解决之道。
每次更改后,请在重新测试前清除浏览器缓存和 Cookie,因为已缓存的 301 重定向可能会掩盖修复效果。仅影响通过某一代理路径访问的用户的条件性循环,在你自己浏览器的单次手动测试中是不可见的。对迁移后站点进行会话回放,可以将真实用户遭遇的间歇性重定向循环和混合内容错误以无限跳转的模式呈现出来。
当 .htaccess 不是合适的工具时
.htaccess 是 Apache 专用的,只在基于 Apache 的主机上生效。在 Nginx 上不存在 .htaccess 文件。强制启用 HTTPS 需要通过监听 80 端口并返回重定向的 server 块来实现:
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
return 301 https://$host$request_uri;
}
return 301 只应放在监听 80 端口的 server 块中;若将其放入 443 端口的 server 块,则会重新引发循环。在现代技术栈中,HTTPS 强制执行通常应在 CDN、平台或负载均衡器层面处理,而非在服务器配置中进行。
重定向生效后,建议通过添加 HSTS 响应头来进一步加固,使浏览器自动通过 HTTPS 连接,完全跳过不安全的 HTTP 请求。HSTS 定义于 RFC 6797;OWASP HSTS 速查表推荐使用 Strict-Transport-Security: max-age=63072000; includeSubDomains; preload。将 preload 视为一扇单向门:将域名从预加载列表中移除的过程非常缓慢,在等待期间,如果你不得不回退到 HTTP,访问者将无法访问该域名及其所有子域名。
选择适合你环境的规则,先以临时 302 部署,验证重定向在一次跳转内正常解析,然后提升为永久 301 并在此基础上叠加 HSTS。这一流程可确保 HTTPS 强制启用,同时避免因重定向循环和缓存错误将一个五分钟的变更演变成一次服务中断。
常见问题
强制启用 HTTPS 时,301 和 302 重定向有什么区别?
301 是永久重定向,302 是临时重定向。浏览器会积极缓存 301 重定向并长期保留,因此一个错误的 301 很难撤销。在测试 HTTPS 重定向时,建议先在 RewriteRule 标志中使用 R(即 302),确认重定向在一次跳转内正常解析后,再将其提升为 R=301 作为永久版本。
如何验证 HTTPS 重定向是否正确解析,而不仅仅是清除浏览器缓存?
在命令行中运行 curl -IL http://yourdomain.com。-I 标志仅请求响应头,-L 标志跟随重定向,因此你可以看到完整的跳转链。正确的配置应返回一个 301,其 Location 响应头指向 https URL,然后在安全地址上返回 200。如果你看到重复的 301 或重定向回 http,则说明存在循环。这种方法是确定性的,不同于检查可能存在缓存的浏览器标签页。
为什么我的 HTTPS 重定向抛出 500 错误而不是进行重定向?
500 错误通常意味着 mod_rewrite 未加载,但你的规则直接调用了 RewriteEngine 或 RewriteRule。请将规则封装在 IfModule mod_rewrite.c 守卫块中,这样当模块不存在时,Apache 会跳过这些规则并以 HTTP 方式提供服务,而不是直接报错。在大多数共享主机和 cPanel 主机上,mod_rewrite 默认启用,但如果你无法确认,使用守卫块是更安全的写法。
.htaccess HTTPS 规则是否适用于 AWS Application Load Balancer 或其他 TLS 终止代理?
标准的 %{HTTPS} off 规则不适用。当 AWS ALB 或类似负载均衡器终止 TLS 时,加密连接在代理层结束,你的 Apache 源站始终只看到普通 HTTP,因此 %{HTTPS} 永远不会为 on,规则会导致 ERR_TOO_MANY_REDIRECTS 循环。应改为使用 RewriteCond %{HTTP:X-Forwarded-Proto} !https,它读取代理设置的请求头,该请求头报告的是访问者的原始连接协议。