我正在尝试创建一个动态虚拟主机条目,目的是将所有流量重定向到.mydomain.com 到 /var/www/html/ 这部分有效,但我还要检查重写条件,检查目录是否存在,如果不存在,那么我想将所有流量重定向到根 /var/www/html/index.php。
这部分不起作用,因为在我测试期间我注意到没有一个重写变量起作用,它们都是空白的,我无法弄清楚为什么这是我的虚拟主机配置
# get the server name from the Host: header
UseCanonicalName Off
# this log format can be split per-virtual-host based on the first field
# LogFormat "%V %h %l %u %t \"%r\" %s %b" vcommon
LogFormat "%{Host}i %h %l %u %t \"%r\" %s %b" vcommon
CustomLog logs/access_log vcommon
<VirtualHost *:80>
ServerName mydomain.com
ServerAlias www.mydomain.com
VirtualDocumentRoot /var/www/html
</VirtualHost>
<VirtualHost *:80>
ServerName vhosts.mydomain.com
ServerAlias *
VirtualDocumentRoot /var/www/html/%1
RewriteEngine on
LogLevel warn rewrite:trace4
# If the request is not for a valid directory
RewriteCond /var/www/html/%1 !-d
RewriteCond %{REQUEST_FILENAME} !-d
# If the request is not for a valid file
RewriteCond %{REQUEST_FILENAME} !-f
# If the request is not for a valid link
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule .* /var/www/html/index.php
</VirtualHost>
你会注意到,我在测试和查看日志文件时可以使用变量的几种用法
[Wed Jul 29 16:56:56.015818 2015] [rewrite:trace2] [pid 23898] mod_rewrite.c(475): [client xx.xx.xx.xx:4863] xx.xx.xx.xx - - [fake.mydomain.com/sid#7f5c89bcf570][rid#7f5c89ed5000/initial] init rewrite engine with requested uri /
[Wed Jul 29 16:56:56.016050 2015] [rewrite:trace3] [pid 23898] mod_rewrite.c(475): [client xx.xx.xx.xx:4863] xx.xx.xx.xx - - [fake.mydomain.com/sid#7f5c89bcf570][rid#7f5c89ed5000/initial] applying pattern '.*' to uri '/'
[Wed Jul 29 16:56:56.018361 2015] [rewrite:trace4] [pid 23898] mod_rewrite.c(475): [client xx.xx.xx.xx:4863] xx.xx.xx.xx - - [fake.mydomain.com/sid#7f5c89bcf570][rid#7f5c89ed5000/initial] RewriteCond: input='/var/www/html/' pattern='!-d' => not-matched
[Wed Jul 29 16:56:56.018411 2015] [rewrite:trace1] [pid 23898] mod_rewrite.c(475): [client xx.xx.xx.xx:4863] xx.xx.xx.xx - - [fake.mydomain.com/sid#7f5c89bcf570][rid#7f5c89ed5000/initial] pass through /
尽管 %1 很好地通过了虚拟目录,但它在 mod 重写规则中不起作用。变量的所有其他用途都产生相同的结果,任何帮助都将不胜感激。
不确定是否有区别,但这是在 Amazon Linux 构建的 AWS 中运行的。
答案1
%1 不是整个 Apache 配置的一种全局变量。
在虚拟文档根它对应于“主机”名称的第一部分,并且在RewriteCond
或中RewriteRule
它表示对捕获组的反向引用前 RewriteCond
. 请参阅 Apache 文档重写条件
扔掉那部分:
RewriteCond /var/www/html/%1 !-d
您对 %1 的使用是错误的,您之前没有任何 RewriteCond,因此 %1 是空字符串。因此基本上您有一个条件,即“如果 /var/www/html/ 不是目录,则执行...”
但显然/var/www/html
是一个目录,这就是为什么你的日志行说
RewriteCond: input='/var/www/html/' pattern='!-d' => not-matched
更新作为您评论的后续内容:
需要理解的是,Apache 由许多不同的部分组成,这些部分是模块。每个模块都有自己的语法。这使得整体非常强大,但可能会造成混淆,就像您的问题一样。每个模块都可以定义一个语法,其中的变量表示%1
每个模块中的其他内容。
可能是我现在更好地理解了你想要做什么:
- 检查请求是否有与其子域对应的目录,如果没有,则发送到
/var/www/html/nosubdomain.php
- 否则,检查请求是否对应于文件/目录/链接,如果不是,则发送到
/var/www/html/nofile.php
步骤 1:获取子域名
要获取子域名,可以使用mod_rewrite的功能来定义和设置环境变量(这里%1
是RewriteCond中捕获的结果):
# Setting environment variable SUBDOMAIN = (subdomain).example.com
RewriteCond %{HTTP_HOST} ^([^\.]*)\.example\.com$
RewriteRule . - [E=SUBDOMAIN:%1]
步骤 2:现在,您可以在重写规则/条件中使用 SUBDOMAIN 变量,并检查与子域对应的目录是否存在。如果不存在,则重定向到定义的页面
# Test if subdomain directory exists, if not, redirect to a
# standard page (/var/www/html/nosubdomain.php).
RewriteCond /var/www/html/%{ENV:SUBDOMAIN} !-d
RewriteRule .* /var/www/html/nosubdomain.php [L]
步骤 3:检查请求的文件是否存在,如果不存在,则发送标准页面 ( /var/www/html/nofile.php
)。为此,最好依靠 Apache 自身检查并使用 ErrorDocument。我们需要一个别名,因为您希望文件nofile.php
位于 VirtualDocumentRoot 之外 ( /var/www/html/subdomain/
)
Alias /nofile.php /var/www/html/nofile.php
ErrorDocument 404 /nofile.php
在您的指令之后将所有这些步骤组合在一起,RewriteEngine On
您应该会得到一个有效的设置,当然您必须根据具体用例进行调整。我已经测试了这个设置,它按我的要求工作,但在 Apache 2.2 上。
如果您在其他地方不使用 SUBDOMAIN,您也可以将步骤 1 和 2 合并在一起:
RewriteCond %{HTTP_HOST} ^([^\.]*)\.example\.com$
RewriteCond /var/www/html/%1 !-d
RewriteRule .* /var/www/html/nosubdomain.php [L]