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 必须写在最前面,开启重写功能。

常用标志

HTTP 跳转到 HTTPS

这个是最常用的配置,网站上 HTTPS 后必须做:

RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}/ [R=301,L]

解释一下:

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 测试字符串 条件模式 [标志]

常用变量

根据 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]

解释一下条件:

场景 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 语法错误导致的。检查:

查看 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/

逐步添加规则

不要一次写一大堆规则,容易出错。一条一条加,每加一条就测试一下。

性能优化

总结

Apache 重定向配置记住这几点:

遇到问题先看错误日志,大部分配置错误都能从日志里找到原因。