星期三, 一月 24, 2007

Apache mod_rewrite & .htaccess for mass VirtualHost

我遇到这样的应用,在 httpd.conf 中 Include virtual.conf,而在 virtual.conf 中全部都是以 "<"VirtualHost">" 方式建立的虚拟主机,每一个虚拟主机的配置大体上一致,是由程序根据注册的情况自动添加的。

现在的要求是,针对每一个站点,可能需要定义一些 Rewrite 规则。因为 "<"VirtualHost">" 是由程序自动生成的,所以不可能在每一个 VirtualHost 中手工更改,而这又是一个商业软件,更改代码也不是那么方便。一种安全一点的考虑是在全局来实现,即编写一个全局的 Rewrite 规则,在所有的虚拟主机中都可以使用。

但这种方法实际上是行不通的。回忆一下 VirtualHost 的基础知识,如果定义了一个 VirtualHost,那么定义的很多全局变量都将失效的,而且原来的主机也需要定义成 VirtualHost 才能继续使用。对 Rewrite 也是如此。实验如下:
httpd.conf
NameVirtualHost 192.168.0.98:80
"<"VirtualHost 192.168.0.98:80">"
ServerName www1.test.com
DocumentRoot /var/www/html/dir
RewriteEngine on (1)
RewriteRule "^/index\.html" "/test.html" (2)
"<"/VirtualHost">"

"<"VirtualHost 192.168.0.98:80">"
ServerName www2.test.com
DocumentRoot /var/www/html/dir2
# RewriteEngine on
# RewriteRule "^/index.html" "/test.html"
"<"/VirtualHost">"

"<"VirtualHost 192.168.0.98:80">"
ServerName www.test.com
DocumentRoot /var/www/html/test
"<"/VirtualHost">"

$ cat /var/www/html/dir/index.html
Index of TEST 1
$ cat /var/www/html/dir/test.html
TEST 1
$ cat /var/www/html/dir2/test2.html
TEST 2
$ cat /var/www/html/test/index.html
INDEX at TEST
$ cat /var/www/html/test/test.html

$ cat /etc/hosts
...
192.168.0.98 www1.test.com
192.168.0.98 www2.test.com
192.168.0.98 www.test.com
192.168.0.98 www.example.com
将(1),(2)分别放置于全局和 VirtualHost 内,就可以看到差异。即使在 VirtualHost 之前增加如下的规则也无效:
RewriteEngine on
RewriteCond %{HTTP_HOST} "!^www.test.com$" [NC,OR]
RewriteCond %{SERVER_NAME} "!^www.test.com$" [NC]
RewriteRule "(.*)" "http://www.test.com$1
这是希望把所有不是到 www.test.com 的请求重定向到 www.test.com(记得修改 /etc/hosts 文件如上),则理论上到 www.example.com 的请求应该会转向 www.test.com,如果这样可以做到,那么我只需要增加一个虚拟主机,然后在这里定义所有的 RewriteRule,再 Rewrite 回去也许是可以的。

但实际上这样也仍然是无效的,最后连接到的仍然是和默认的一样:www1.test.com──这是符合 VirtualHost 的基本原理的。所以 VirtualHost “优先级”更高,会覆盖掉全局的 Rewrite 设置。

那么另一个解决办法就是利用 .htaccess 来实现了。所有虚拟主机的 DocumentRoot 均是 /www/users/$virtualhostname,则方法是:
$ cat httpd.conf
"<"Directory "/www/users"">"
AllowOverride FileInfo
Order Allow, Deny
Allow From All
"<"/Directory">"

$ cat /www/users/www.test04.com/.htaccess
RewriteEngine on
RewriteRule "^index\.html" "/index.php"
注意这里的正则表达式是"^index\.html"而不是象全局和 VirtualHost 段中使用的 "^/index\.html",这是因为 .htaccess 是在指定的 Directory 中,所以其使用的是一个类似于相对路径的概念,当然这里是 URL 的一个相对路径。所以"^/index\.html"将得不到任何匹配。而 RewriteRule 部分的正则匹配串则是 URL 部分去除主机名后的那部分路径,并一定以"/"开头──也就是 DocumentRoot

这样就基本上可以实现了,但开放 .htaccess 以后可能会有负载问题,目前来看,可以考虑使用 PAM 来实现对于资源的控制看是否可行?

没有评论: