Apache 重定向配置完全指南
Apache 配置重定向主要靠 .htaccess 文件和 mod_rewrite 模块。相比 Nginx,Apache 的配置更灵活,但也更容易写错。
用过虚拟主机的都知道,很多时候你没有服务器配置权限,只能通过 .htaccess 文件来配置重定向。这个文件放在网站根目录,Apache 会自动读取。
.htaccess 基础
什么是 .htaccess
.htaccess 是 Apache 的分布式配置文件,可以在不修改主配置文件的情况下,对特定目录进行配置。
文件名就叫 .htaccess,注意前面有个点,是隐藏文件。Windows 下可能看不到,需要显示隐藏文件。
确认 mod_rewrite 已启用
重定向功能需要 mod_rewrite 模块,大部分服务器都默认开启了。如果没开启,需要先启用:
# Ubuntu/Debian
sudo a2enmod rewrite
sudo systemctl restart apache2
# CentOS/RHEL
# 编辑 /etc/httpd/conf/httpd.conf
# 找到这行并取消注释:
LoadModule rewrite_module modules/mod_rewrite.so
# 重启 Apache
sudo systemctl restart httpd
允许 .htaccess 覆盖配置
服务器配置里需要允许 .htaccess 覆盖设置:
<Directory /var/www/html>
AllowOverride All
</Directory>
虚拟主机一般都配置好了,自己搭服务器的话需要检查一下。
Redirect - 简单重定向
最简单的重定向方式,不需要正则表达式:
基本语法
Redirect 状态码 原路径 目标URL
301 永久重定向
# 单个页面跳转
Redirect 301 /old-page.html https://example.com/new-page.html
# 整个目录跳转
Redirect 301 /old-dir https://example.com/new-dir
# 跳转到其他域名
Redirect 301 / https://new-domain.com/
302 临时重定向
Redirect 302 /maintenance.html https://example.com/temp-page.html
# 或者用 temp 关键字
Redirect temp /old-page.html /new-page.html
💡 Redirect 的局限
Redirect 指令很简单,但功能有限。不支持正则匹配,不能根据条件判断。复杂的重定向还是得用 RewriteRule。
RewriteRule - 强大的重写规则
RewriteRule 是 Apache 重定向的核心,支持正则表达式和各种条件判断。
基本结构
RewriteEngine On
RewriteRule 正则表达式 替换目标 [标志]
RewriteEngine On 必须写在最前面,开启重写功能。
常用标志
[R=301]- 301 永久重定向[R=302]- 302 临时重定向[L]- Last,停止处理后续规则[NC]- No Case,不区分大小写[QSA]- Query String Append,保留查询参数[NE]- No Escape,不转义特殊字符
HTTP 跳转到 HTTPS
这个是最常用的配置,网站上 HTTPS 后必须做:
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}/ [R=301,L]
解释一下:
RewriteCond %{HTTPS} off- 条件:如果不是 HTTPS^(.*)$- 匹配所有 URLhttps://%{HTTP_HOST}/- 跳转到 HTTPS,保留域名和路径[R=301,L]- 301 重定向,停止后续规则
www 和非 www 统一
把非 www 跳转到 www:
RewriteEngine On
RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
RewriteRule ^(.*)$ https://www.example.com/ [R=301,L]
或者反过来,把 www 跳转到非 www:
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\.example\.com$ [NC]
RewriteRule ^(.*)$ https://example.com/ [R=301,L]
整站跳转到新域名
RewriteEngine On
RewriteCond %{HTTP_HOST} ^old-domain\.com$ [NC,OR]
RewriteCond %{HTTP_HOST} ^www\.old-domain\.com$ [NC]
RewriteRule ^(.*)$ https://new-domain.com/ [R=301,L]
[OR] 表示或条件,匹配任意一个域名都跳转。
RewriteCond - 条件判断
RewriteCond 用来设置重写条件,只有满足条件才执行后面的 RewriteRule。
基本语法
RewriteCond 测试字符串 条件模式 [标志]
常用变量
%{HTTP_HOST}- 域名(如 example.com)%{REQUEST_URI}- 请求路径(如 /page?id=123)%{QUERY_STRING}- 查询参数(如 id=123)%{HTTPS}- 是否 HTTPS(on 或 off)%{HTTP_USER_AGENT}- 浏览器 User-Agent%{REMOTE_ADDR}- 访客 IP 地址
根据 User-Agent 跳转
移动设备跳转到移动版:
RewriteEngine On
RewriteCond %{HTTP_USER_AGENT} "android|iphone|ipad|ipod" [NC]
RewriteRule ^(.*)$ https://m.example.com/ [R=302,L]
根据 IP 地址跳转
RewriteEngine On
RewriteCond %{REMOTE_ADDR} ^192\.168\.1\.
RewriteRule ^(.*)$ /admin/ [L]
根据查询参数跳转
RewriteEngine On
RewriteCond %{QUERY_STRING} ^id=([0-9]+)$
RewriteRule ^article$ /post/%1? [R=301,L]
%1 表示 RewriteCond 里第一个括号匹配的内容。注意结尾的 ?,用来去掉原来的查询参数。
常见配置场景
场景 1:强制 HTTPS + 统一 www
这个配置把所有请求都跳转到 https://www.example.com:
RewriteEngine On
# 强制 HTTPS
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}/ [R=301,L]
# 强制 www
RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
RewriteRule ^(.*)$ https://www.example.com/ [R=301,L]
场景 2:去掉 URL 中的 .html
RewriteEngine On
# 如果访问 /page.html,跳转到 /page
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.html -f
RewriteRule ^(.+)\.html$ / [R=301,L]
# 内部重写 /page 到 /page.html
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.html -f
RewriteRule ^(.+)$ .html [L]
解释一下条件:
!-d- 不是目录!-f- 不是文件-f- 文件存在
场景 3:WordPress 伪静态
WordPress 的标准 .htaccess 配置:
# BEGIN WordPress
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
# END WordPress
场景 4:旧 URL 结构迁移
把旧的 URL 格式跳转到新格式:
RewriteEngine On
# /article.php?id=123 → /post/123
RewriteCond %{QUERY_STRING} ^id=([0-9]+)$
RewriteRule ^article\.php$ /post/%1? [R=301,L]
# /blog/2025/02/13/title → /post/2025-02-13-title
RewriteRule ^blog/([0-9]{4})/([0-9]{2})/([0-9]{2})/(.*)$ /post/--- [R=301,L]
场景 5:禁止特定 User-Agent 访问
RewriteEngine On
RewriteCond %{HTTP_USER_AGENT} "badbot|scraper" [NC]
RewriteRule .* - [F,L]
[F] 表示 Forbidden,返回 403 错误。
常见错误和坑
1. 500 Internal Server Error
这个错误通常是 .htaccess 语法错误导致的。检查:
- 正则表达式是否正确转义(
\.而不是.) - 标志是否写对(
[R=301,L]而不是[R301L]) - 是否有多余的空格或换行
查看 Apache 错误日志:
# Ubuntu/Debian
tail -f /var/log/apache2/error.log
# CentOS/RHEL
tail -f /var/log/httpd/error_log
2. 重定向循环
最常见的原因是条件判断不够严格:
# 错误 - 会导致循环
RewriteRule ^(.*)$ https://example.com/ [R=301,L]
# 正确 - 加上 HTTPS 判断
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://example.com/ [R=301,L]
3. 查询参数丢失
默认情况下,RewriteRule 不会保留查询参数:
# 错误 - 参数会丢失
RewriteRule ^old-page$ /new-page [R=301,L]
# 正确 - 加上 QSA 标志
RewriteRule ^old-page$ /new-page [R=301,L,QSA]
4. 正则表达式转义问题
.htaccess 里的正则需要双重转义:
# 错误 - . 会匹配任意字符
RewriteRule ^page.html$ /new-page [R=301,L]
# 正确 - 转义 .
RewriteRule ^page\.html$ /new-page [R=301,L]
5. RewriteBase 问题
如果网站不在根目录,需要设置 RewriteBase:
# 网站在 /subfolder/ 目录下
RewriteEngine On
RewriteBase /subfolder/
RewriteRule ^old-page$ new-page [R=301,L]
调试技巧
开启 Rewrite 日志
在主配置文件或虚拟主机配置里添加:
LogLevel alert rewrite:trace3
然后查看日志:
tail -f /var/log/apache2/error.log | grep rewrite
测试重定向
# 用 curl 测试
curl -I http://example.com/old-page
# 跟随重定向
curl -IL http://example.com/old-page
# 或者用我们的工具
# https://www.301check.com/v1/
逐步添加规则
不要一次写一大堆规则,容易出错。一条一条加,每加一条就测试一下。
性能优化
- .htaccess 会影响性能,因为 Apache 每次请求都要读取文件
- 如果有服务器配置权限,建议把规则写到虚拟主机配置里
- 避免过多的
RewriteCond判断 - 把常用的规则放在前面
总结
Apache 重定向配置记住这几点:
- 简单跳转用
Redirect,复杂的用RewriteRule - 正则表达式记得转义(
\.) - 保留查询参数加
[QSA]标志 - 301 重定向用
[R=301,L] - 改完配置测试一下,避免 500 错误和循环跳转
- 查看日志排查问题
遇到问题先看错误日志,大部分配置错误都能从日志里找到原因。