Apache2配置子域名映射子目录出现重定向超限500报错排查
重写规则的问题根源
你写的规则触发了Apache内部重定向死循环:
- 当访问
test1.example.com时,第一次匹配规则,请求被重写到/test1/对应路径 - Apache完成第一次重写后,会重新对新的路径执行重写规则匹配,此时
HTTP_HOST字段仍然是test1.example.com,会再次命中你写的重写规则,把路径二次重写为/test1/test1/对应路径 - 这个过程会不断循环,直到触发Apache默认的10次内部重定向上限,就会抛出你看到的错误日志,返回500状态码。
另外你原来的规则还有个小瑕疵:正则里的.没有转义,.在正则语法中代表匹配任意字符,可能导致test1xexample.com这类非预期域名也命中规则。
现有.htaccess规则的修复方式
只需要给每条重写规则增加一个前置判断,排除已经指向对应子目录的请求,避免重复重写即可,修正后的规则如下:
RewriteEngine On # test1子域名规则 RewriteCond %{HTTP_HOST} ^test1\.example\.com$ [NC] RewriteCond %{REQUEST_URI} !^/test1/ RewriteRule ^(.*)$ /test1/$1 [L,QSA] # test2子域名规则 RewriteCond %{HTTP_HOST} ^test2\.example\.com$ [NC] RewriteCond %{REQUEST_URI} !^/test2/ RewriteRule ^(.*)$ /test2/$1 [L,QSA]
如果你的Apache版本高于2.3.9,也可以直接把规则里的L标记替换为END标记,END会直接终止整个重写流程,不会触发新一轮重写匹配,也能解决循环问题,示例:
RewriteCond %{HTTP_HOST} ^test1\.example\.com$ [NC] RewriteRule ^(.*)$ /test1/$1 [END,NC,QSA]
更优的替代实现方案
用.htaccess重写的方式本质是请求在Apache内部做了二次转发,性能和可维护性都不如以下方案:
- 最规范的方案:配置基于域名的虚拟主机(VirtualHost)
直接给两个子域名分别编写独立的VirtualHost配置块,将子域名的文档根目录(DocumentRoot)直接指向对应的子目录,完全不需要重写规则,没有循环风险,性能最好。配置示例:
配置完成后执行# test1.example.com 虚拟主机配置 <VirtualHost *:80> ServerName test1.example.com DocumentRoot /var/www/你的站点根目录/test1 <Directory /var/www/你的站点根目录/test1> Options Indexes FollowSymLinks AllowOverride All Require all granted </Directory> </VirtualHost> # test2.example.com 虚拟主机配置 <VirtualHost *:80> ServerName test2.example.com DocumentRoot /var/www/你的站点根目录/test2 <Directory /var/www/你的站点根目录/test2> Options Indexes FollowSymLinks AllowOverride All Require all granted </Directory> </VirtualHost>a2ensite 对应的配置文件名启用站点,再执行systemctl reload apache2重载服务即可生效。 - 面板快捷方案:如果你使用宝塔、cPanel这类可视化运维面板,直接在面板的「子域名」功能中添加子域名时,将根目录选择为对应子目录即可,面板会自动生成正确的虚拟主机配置,无需手动修改代码。
内容的提问来源于stack exchange,提问作者Franz Andreani
相关产品推荐
相关产品推荐

