如果要使用apache建站.那你一定要看完这个.如果你没有看完.那会遇到一大堆问题.等你问题出来了再一个一个找.那我看你要花更多的时间去解答问题.那时你会觉的力不可行也…..所以说重了一点.这个是最常重要的文档.下面这个文档适合在于用原代码安装有朋友查看.不过用软包直接安装的.他们的这些文档不是放在同一个文档里.而是分开的.所以你要花更多的时间去了解.
术语”虚拟主机“是指在一个机器上运行多个网站(比如:www.company1.com和www.company2.com)。如果每个网站拥有不同的IP地址,则虚拟主机可以是”基于IP”的;如果只有一个IP地址,也可以是”基于主机名”的,其实现对最终用户是透明的。
Apache是率先支持基于IP的虚拟主机的服务器之一。1.1及其更新版本同时支持基于IP和基于主机名的虚拟主机,今后,不同的虚拟主机有时会被称为”基于主机”或”非IP虚拟主机”。
下列文档会阐述Apache1.3及其更新版本所支持的虚拟主机的所有细节。
虚拟主机支持
* 基于主机名的虚拟主机(一个IP地址,多个网站)
* 基于IP地址的虚拟主机(每个站点拥有一个的独立IP地址)
* 虚拟主机的普通配置示例
* 文件描述符限制(在日志文件过多的情况下会产生的限制)
* 动态配置大量虚拟主机
* 深入讨论虚拟主机的匹配
配置指令
* <VirtualHost>
* NameVirtualHost
* ServerName
* ServerAlias
* ServerPath
如果要调试你的虚拟主机配置,你会发现Apache的 -S 命令行开关很有用。比如:
/usr/local/apache2/bin/httpd -S
此命令会输出Apache解析配置文件的详细描述,仔细检查IP地址和主机名会有助于纠正配置错误。
本文档说明了如何使用基于域名的虚拟主机。
基于域名的虚拟主机和基于IP的虚拟主机比较
基于IP的虚拟主机使用连接的IP地址来决定相应的虚拟主机。这样,你就需要为每个虚拟主机分配一个独立的IP地址。而基于域名的虚拟主机是根据客户端提交的HTTP头中标识主机名的部分决定的。使用这种技术,很多虚拟主机可以共享同一个IP地址。
基于域名的虚拟主机相对比较简单,因为你只需要配置你的DNS服务器将每个主机名映射到正确的IP地址,然后配置Apache HTTP服务器,令其辨识不同的主机名就可以了。基于域名的服务器也可以缓解IP地址不足的问题。所以,如果没有特殊原因使你必须使用基于IP的虚拟主机,您最好还是使用基于域名的虚拟主机。下列情况下,你可能会想要使用基于IP的虚拟主机:
* 一些古董级的客户端与基于域名的虚拟主机不兼容。为了与基于域名的虚拟主机兼容,客户端必须发送”Host”头。HTTP/1.1规范中对此做了要求。而所有现在常见的仅支持HTTP/1.0的旧版本浏览器都以附加的方式实现了这个要求。如果你又想支持这些老浏览器,又想使用基于域名的虚拟主机。我们提供了一个技术方案,你可以在本文末尾看到它。
* SSL协议先天特性决定了基于域名的虚拟主机无法成为SSL安全服务器。
* 一些操作系统和网络设备实现的带宽管理技术无法在多个主机共享一个IP的情况下区别它们。
使用基于域名的虚拟主机
相关模块:
* core
相关指令:
* DocumentRoot
* NameVirtualHost
* ServerAlias
* ServerName
* ServerPath
* <VirtualHost>
为了使用基于域名的虚拟主机,你必须指定服务器IP地址(和可能的端口)来使主机接受请求,这个可以用NameVirtualHost指令来进行配置。如果服务器上所有的IP地址都会用到,你可以用”*”作为NameVirtualHost的参数。如果你打算使用多端口(如运行SSL)你必须在参数中指定一个端口号,比如”*:80″。请注意,在NameVirtualHost指令中指定IP地址并不会使服务器自动侦听那个IP地址。请参阅设置Apache使用的地址和端口一章获取更多详情。另外,这里设定的IP地址必须对应服务器上的一个网络接口。
下一步就是为每个虚拟主机建立<VirtualHost>段。<VirtualHost>的参数与NameVirtualHost的参数必须是一样的(比如说,一个IP地址或”*”代表的所有地址)。在每个<VirtualHost>段中,至少要有一个ServerName指令来指定伺服哪个主机和一个DocumentRoot指令来说明这个主机的内容位于文件系统的什么地方。
取消中心主机(Mainhost)
如果你想在现有的web服务器上增加虚拟主机,你必须也为现存的主机建造一个<VirtualHost>定义块。这个虚拟主机中ServerName和DocumentRoot所包含的内容应该与全局的ServerName和DocumentRoot保持一致。还要把这个虚拟主机放在配置文件的最前面,来让它扮演默认主机的角色。
比如说,假设你正在为域名www.domain.tld提供服务,而你又想在同一个IP地址上增加一个名叫www.otherdomain.tld的虚拟主机,你只需在httpd.conf中加入以下内容:
NameVirtualHost *:80
<VirtualHost *:80>
ServerName www.domain.tld
ServerAlias domain.tld *.domain.tld
DocumentRoot /www/domain
</VirtualHost>
<VirtualHost *:80>
ServerName www.otherdomain.tld
DocumentRoot /www/otherdomain
</VirtualHost>
当然,你可以用一个固定的IP地址来代替NameVirtualHost和<VirtualHost>指令中的”*”号,以达到一些特定的目的。比如说,你可能会希望在一个IP地址上运行一个基于域名的虚拟主机,而在另外一个IP地址上运行一个基于IP的或是另外一套基于域名的虚拟主机。
很多服务器希望自己能通过不只一个域名被访问。我们可以把ServerAlias指令放入<VirtualHost>小节中来解决这个问题。比如说在上面的第一个<VirtualHost>配置段中ServerAlias指令中列出的名字就是用户可以用来访问同一个web站点的其它名字:
ServerAlias domain.tld *.domain.tld
这样,所有对域domain.tld的访问请求都将由虚拟主机www.domain.tld处理。通配符标记”*”和”?”可以用于域名的匹配。当然你不能仅仅搞个名字然后把它放到ServerName或ServerAlias里就算完了。你必须先在你的DNS服务器上进行配置,将这些名字和您服务器上的一个IP地址建立映射关系。
最后,你可以把其他一些指令放入<VirtualHost>段中,以更好的配置一个虚拟主机。大部分指令都可以放入这些<VirtualHost>段中以改变相应虚拟主机配置。如果您想了解一个特定的指令是否可以这样运用,请参见指令的作用域。主服务器(main server)范围内的配置指令(在所有<VirtualHost>配置段之外的指令)仅在它们没有被虚拟主机的配置覆盖时才起作用。
这样,当一个请求到达的时候,服务器会首先检查它是否使用了一个能和NameVirtualHost相匹配的IP地址。如果能够匹配,它就会查找每个与这个IP地址相对应的<VirtualHost>段,并尝试找出一个与请求的主机名相同的ServerName或ServerAlias配置项。如果找到了,它就会使用这个服务器。否则,将使用符合这个IP地址的第一个列出的虚拟主机。
综上所述,第一个列出的虚拟主机充当了默认虚拟主机的角色。当一个IP地址与NameVirtualHost指令中的配置相符的时候,主服务器中的DocumentRoot将永远不会被用到。所以,如果你想创建一段特殊的配置用于处理不对应任何一个虚拟主机的请求的话,你只要简单的把这段配置放到<VirtualHost>段中,并把它放到配置文件的最前面就可以了。
与旧版浏览器的兼容性
前面提过,有些浏览器无法对基于域名的虚拟主机发送必要的数据,从而使其无法正常工作。这些浏览器将会收到由配置中符合那个IP地址的第一个列出的虚拟主机发出的页面(基于域名的主虚拟主机)。
究竟什么算旧?
请注意,当我们说到旧的时候,我们并不是真的说它们很古老。其实现实中您未必就能用上这些浏览器。现在几乎所有的浏览器都会发送基于域名的虚拟主机所必须的Host头了。
虽然有点麻烦。但您还是有可能会用到ServerPath指令,以下是一个配置实例:
NameVirtualHost 111.22.33.44
<VirtualHost 111.22.33.44>
ServerName www.domain.tld
ServerPath /domain
DocumentRoot /web/domain
</VirtualHost>
以上这些说明了什么呢?它说明一个具有”/domain”开头的任何URI都会为www.domain.tld这个虚拟主机所伺服。这意味着这个页面可以由http://www.domain.tld/domain/的形式为所有的浏览器所访问。能够发送”Host:”头的浏览器也能使用http://www.domain.tld/这种形式来访问它。
为了达到这样的目的。您先要在您的主虚拟主机的页面上放一个到http://www.domain.tld/domain/的链接。然后,确保在虚拟主机的页面中使用的全是相对链接(诸如:”file.html”或”../icons/image.gif”)或者是包含/domain/这个前缀(比如:”http://www.domain.tld/domain/misc/file.html”或”/domain/misc/file.html”)。
完成这些可能需要一些尝试,但遵照上述指导将会确保你的页面能够为所有的浏览器所正确显示,不论新旧。
系统需求
就像它的名字”基于IP”所暗示的那样,这样的服务器中每个基于IP的虚拟主机必须拥有不同的IP地址。可以通过配备多个真实的物理网络接口来达到这一要求,也可以使用几乎所有流行的操作系统都支持的虚拟界面来达到这一要求(详情请参见您的系统文档,这种功能一般被称作”IP别名”,一般用”ifconfig”命令来进行设置)。
如何配置Apache
有两种配置方法来使apache支持多主机:为每个虚拟主机运行不同的httpd守护进程;或者用同一个守护进程来支持所有虚拟主机。
以下情况使用多个守护进程:
* 出于安全的考虑,比如说公司甲不希望公司乙的任何人能用除web以外的方式访问到他们的数据。在这种情况下,您需要启动两个守护进程。每个进程都使用不同的User, Group, Listen, ServerRoot设置。
* 您能够为机器上的每个IP地址提供内存和文件描述符需求。您只能Listen一个”通配符型”地址或一个特定的地址。所以不管出于什么原因,如果您需要侦听一个特定的地址,您就必须同时侦听所有特定的地址。(尽管可以让一个httpd侦听N-1个地址,而让另一个侦听剩下的地址)
以下情况使用单一守护进程:
* httpd的配置可以为多个虚拟主机共享而不引起麻烦。
* 机器要接受大量的访问请求,从而多启动一个守护进程会导致性能大幅度降低。
设置多个守护进程
为每个虚拟主机创建一个不同的httpd安装。每次安装都在配置文件中使用Listen指令指定守护进程伺服的IP地址(或虚拟主机)。比如:
Listen www.smallco.com:80
建议您使用IP地址来取代域名(理由请参见关于DNS和Apache)。
配置拥有多个虚拟主机的单一守护进程
在这种情况下,单一的httpd将伺服所有对主服务器和虚拟主机的请求。而配置文件中的VirtualHost指令将为每个虚拟主机配置不同的ServerAdmin, ServerName, DocumentRoot, ErrorLog, TransferLog, CustomLog 。例如:
<VirtualHost www.smallco.com>
ServerAdmin webmaster@mail.smallco.com
DocumentRoot /groups/smallco/www
ServerName www.smallco.com
ErrorLog /groups/smallco/logs/error_log
TransferLog /groups/smallco/logs/access_log
</VirtualHost>
<VirtualHost www.baygroup.org>
ServerAdmin webmaster@mail.baygroup.org
DocumentRoot /groups/baygroup/www
ServerName www.baygroup.org
ErrorLog /groups/baygroup/logs/error_log
TransferLog /groups/baygroup/logs/access_log
</VirtualHost>
建议您使用IP地址来取代域名(理由请参见关于DNS和Apache)。
除了创建进程的指令和其他一些指令外,几乎所有的配置指令都能用于<VirtualHost>指令中。您可以使用指令索引在作用域中查询一个指令是否可以用于<VirtualHost>指令。
如果使用了suEXEC包装,那么SuexecUserGroup指令也可以在<VirtualHost>段中使用。
安全警示:当指定日志文件时,请记住有安全风险。一些别有用心的人会在那个目录拥有写权限。
本文档试图解释一些在设置虚拟主机时经常问及的问题。这些示例向你展示了如何在一个服务器上通过基于域名的或是基于IP的虚拟主机来部署多个web站点。另一份关于如何在一个代理服务器后构建基于多个服务器的站点的说明文档也很快就会出来。
在一个IP地址上运行多个基于域名的web站点
您的服务器有只一个IP地址,而在DNS中有很多域名(CNAMES)映射到这个机器。您而您想要在这个机器上运行www.example.com和www.example.org两个站点。
注意
在您的Apache服务器配置中创建一个虚拟主机并不会自动在您的DNS中对主机名做相应更新。您必须自己在DNS中添加域名来指向您的IP地址。否则别人是无法看到您的web站点的。您可以在您的hosts文件中添加这一条目来进行测试,但这种方法仅适用于那些有这些hosts文件的机器来使用。
服务器配置
# 确保Apache在监听80端口
Listen 80
# 为虚拟主机在所有IP地址上监听
NameVirtualHost *:80
<VirtualHost *:80>
DocumentRoot /www/example1
ServerName www.example.com
# 你可以在这里添加其他指令
</VirtualHost>
<VirtualHost *:80>
DocumentRoot /www/example2
ServerName www.example.org
# 你可以在这里添加其他指令
</VirtualHost>
因为星号匹配所有IP地址,所以主服务器不接收任何请求。因为www.example.com首先出现在配置文件中,所以它拥有最高优先级,可以认为是默认或主服务器。这意味着如果一个请求不能与某个ServerName指令相匹配,它将会由第一个<VirtualHost>段所伺服。
注意
如果您愿意,您可以用确定的IP地址来取代”*”。在这种情况下,VirtualHost的参数必须与NameVirtualHost的参数相符:
NameVirtualHost 172.20.30.40
<VirtualHost 172.20.30.40>
# 其他 …
然而,当您的IP地址无法确定的时候,使用”*”是很方便的,比如说,您的ISP给您配置的是动态IP地址,而您又使用了某种动态域名解析系统时。因为”*”匹配任何IP地址,所以在这种情况下,不论IP地址如何变化,您都不需要另外进行配置。
上述配置就是您在绝大多数情况下使用基于域名的虚拟主机时将要用到的。事实上,仅在一种情况下这样的配置不会让您满意:您想为不同的IP地址或是端口提供不同的内容。
在多于一个IP的情况下使用基于域名的虚拟主机
注意
在这里讨论的任何技术都可以推广到使用任意数量的IP地址。
服务器有两个IP地址。一个(172.20.30.40)用于主服务器server.domain.com ,另外一个(172.20.30.50)用于构建两个或多个虚拟主机。
服务器配置
Listen 80
# “主”服务器运行于:172.20.30.40
ServerName server.domain.com
DocumentRoot /www/mainserver
# 这是另外一个IP地址
NameVirtualHost 172.20.30.50
<VirtualHost 172.20.30.50>
DocumentRoot /www/example1
ServerName www.example.com
# 你可以在这里添加其他指令 …
</VirtualHost>
<VirtualHost 172.20.30.50>
DocumentRoot /www/example2
ServerName www.example.org
# 你可以在这里添加其他指令 …
</VirtualHost>
任何不是针对172.20.30.50的请求都将由主服务器来伺服。而提交给172.20.30.50却没有主机名或没有”Host:”头的请求,都将由www.example.com伺服。
在不同的IP的地址(比如一个内部和一个外部地址)上提供相同的内容
服务器有两个IP地址(192.168.1.1和172.20.30.40)。这个机器位于内部(局域网)网络和外部(广域网)之间。在外部,域名server.example.com指向外部地址(172.20.30.40),而在内部则指向内部地址(192.168.1.1)。
服务器可以为来自内部和外部的请求提供同样的内容,您只需要一个<VirtualHost>配置段就可以了。
服务器配置
NameVirtualHost 192.168.1.1
NameVirtualHost 172.20.30.40
<VirtualHost 192.168.1.1 172.20.30.40>
DocumentRoot /www/server1
ServerName server.example.com
ServerAlias server
</VirtualHost>
现在,从不同的网络提交的请求都会由同一个<VirtualHost>段来伺服。
注意
在内网中,您可以使用server这个名字来代替server.example.com这个全名。
跟上面一样,在上述的例子里,您可以用”*”来代替具体的IP地址,这样就可以对所有的地址都返回相同的内容了。
在不同的端口上运行不同的站点
如果您想让同一个IP的不同端口伺服多个域名。您可以借助在NameVirtualHost指令中定义端口的方法来达到这个目的。如果您想使用不带”name:port”的<VirtualHost name:port>或是直接用Listen指令,您的配置将无法生效。
服务器配置
Listen 80
Listen 8080
NameVirtualHost 172.20.30.40:80
NameVirtualHost 172.20.30.40:8080
<VirtualHost 172.20.30.40:80>
ServerName www.example.com
DocumentRoot /www/domain-80
</VirtualHost>
<VirtualHost 172.20.30.40:8080>
ServerName www.example.com
DocumentRoot /www/domain-8080
</VirtualHost>
<VirtualHost 172.20.30.40:80>
ServerName www.example.org
DocumentRoot /www/otherdomain-80
</VirtualHost>
<VirtualHost 172.20.30.40:8080>
ServerName www.example.org
DocumentRoot /www/otherdomain-8080
</VirtualHost>
建立基于IP的虚拟主机
一个有两个IP地址(172.20.30.40和172.20.30.50)分别对应域名www.example.com和www.example.org的配置如下:
服务器配置
Listen 80
<VirtualHost 172.20.30.40>
DocumentRoot /www/example1
ServerName www.example.com
</VirtualHost>
<VirtualHost 172.20.30.50>
DocumentRoot /www/example2
ServerName www.example.org
</VirtualHost>
如果存在主服务器,那么对没有出现在任一个<VirtualHost>段中的请求(比如,对localhost的请求)都会由主服务器来伺服。
混用基于端口和基于IP的虚拟主机
如果您的服务器有两个IP地址(172.20.30.40和172.20.30.50)分别对应域名www.example.com和www.example.org 。对每个域名,您都希望在80端口和8080端口发布您的网站。您可以这样配置:
服务器配置
Listen 172.20.30.40:80
Listen 172.20.30.40:8080
Listen 172.20.30.50:80
Listen 172.20.30.50:8080
<VirtualHost 172.20.30.40:80>
DocumentRoot /www/example1-80
ServerName www.example.com
</VirtualHost>
<VirtualHost 172.20.30.40:8080>
DocumentRoot /www/example1-8080
ServerName www.example.com
</VirtualHost>
<VirtualHost 172.20.30.50:80>
DocumentRoot /www/example2-80
ServerName www.example.org
</VirtualHost>
<VirtualHost 172.20.30.50:8080>
DocumentRoot /www/example2-8080
ServerName www.example.org
</VirtualHost>
混用基于域名和基于IP的虚拟主机
您想在一些地址上配置基于域名的虚拟主机而在另外一些地址上配置基于IP的虚拟主机。
服务器配置
Listen 80
NameVirtualHost 172.20.30.40
<VirtualHost 172.20.30.40>
DocumentRoot /www/example1
ServerName www.example.com
</VirtualHost>
<VirtualHost 172.20.30.40>
DocumentRoot /www/example2
ServerName www.example.org
</VirtualHost>
<VirtualHost 172.20.30.40>
DocumentRoot /www/example3
ServerName www.example3.net
</VirtualHost>
# IP-based
<VirtualHost 172.20.30.50>
DocumentRoot /www/example4
ServerName www.example4.edu
</VirtualHost>
<VirtualHost 172.20.30.60>
DocumentRoot /www/example5
ServerName www.example5.gov
</VirtualHost>
将<Virtual_host>和mod_proxy模块一起使用
下面的例子允许一个前端机器代理一个运行在其他机器上的虚拟主机。在如下示例中,在192.168.111.2机器上配置了一个同名的虚拟主机。这样,万一在同一台机器上代理了多个主机名,ProxyPreserveHost On 指令能确保指定的主机名顺利通过代理。
<VirtualHost *:*>
ProxyPreserveHost On
ProxyPass / http://192.168.111.2
ProxyPassReverse / http://192.168.111.2/
ServerName hostname.example.com
</VirtualHost>
使用”_default_”虚拟主机
为所有端口配置”_default_”虚拟主机
这样配置可以捕获所有指向没指定的IP地址和端口的请求。比如:一个没被任何虚拟主机使用的地址/端口对。
服务器配置
<VirtualHost _default_:*>
DocumentRoot /www/default
</VirtualHost>
这样一个使用通配符端口的默认虚拟主机可以有效的防止请求被主服务器接收。
如果一个地址/端口对已经被一个基于域名的虚拟主机使用,那么”_default_”虚拟主机决不会处理发向这个地址/端口对的请求。如果一个”Host:”请求头中包含未知信息,或者干脆就没有,那么它会被第一个基于域名的虚拟主机(也就是在配置文件中最先出现的使用了那个地址/端口对的虚拟主机)处理。
您可以用AliasMatch或RewriteRule来重写任何请求,使它指向一个简单信息页面(或脚本)。
为不同的端口配置”_default_”虚拟主机
与第一种一样,但我们想让服务器侦听很多端口而第二个”_default_”虚拟主机单独侦听80端口。
服务器配置
<VirtualHost _default_:80>
DocumentRoot /www/default80
# …
</VirtualHost>
<VirtualHost _default_:*>
DocumentRoot /www/default
# …
</VirtualHost>
侦听80端口的”_default_”虚拟主机(必须出现在所有使用通配符端口的虚拟主机之前)会捕获所有发向一个未指定的IP地址的请求。主服务器将不会用于伺服任何请求。
为单独一个端口配置”_default_”虚拟主机
如果我们只想在80端口上建立唯一的一个”_default_”虚拟主机,我们应该这样配置:
服务器配置
<VirtualHost _default_:80>
DocumentRoot /www/default
…
</VirtualHost>
发向一个未指定地址的80端口的请求将会由这个虚拟主机伺服;而发向未设定地址的其他端口的请求则由主服务器伺服。
将一个基于域名的虚拟主机移植为一个基于IP的虚拟主机
如果一个具有www.example.org域名的虚拟主机(就是基于域名配置示例中的第二个)得到了自己的IP地址。为了避免一些域名服务器或代理服务器在移植期间仍对这个域名做老的解析,我们可以采用一种过渡方法:同时提供新旧两个IP地址的解析。
达到这个目的很简单。因为我们只要简单的把新地址(172.20.30.50)加入VirtualHost指令就行了。
服务器配置
Listen 80
ServerName www.example.com
DocumentRoot /www/example1
NameVirtualHost 172.20.30.40
<VirtualHost 172.20.30.40 172.20.30.50>
DocumentRoot /www/example2
ServerName www.example.org
# …
</VirtualHost>
<VirtualHost 172.20.30.40>
DocumentRoot /www/example3
ServerName www.example.net
ServerAlias *.example.net
# …
</VirtualHost>
现在这个虚拟主机就可以用新地址(表现为一个基于IP的虚拟主机)和旧地址(表现为一个基于域名的虚拟主机)同时进行访问了。
使用ServerPath指令
如果我们在同一个服务器上运行了两个基于域名的虚拟主机。为了匹配正确的虚拟主机,客户端必须发送正确的”Host:” 头。而旧的使用HTTP/1.0的客户端无法发送这样的头,这样Apache就无法辨别客户端想要连接哪个虚拟主机(会用主虚拟主机来伺服这个请求)。为了尽量提供向下兼容性,我们可以提供一个主虚拟主机来返回一个页面,在页面中加入指向基于域名的虚拟主机的URL前缀的链接。
服务器配置
NameVirtualHost 172.20.30.40
<VirtualHost 172.20.30.40>
# 主虚拟主机
DocumentRoot /www/subdomain
RewriteEngine On
RewriteRule ^/.* /www/subdomain/index.html
# …
</VirtualHost>
<VirtualHost 172.20.30.40>
DocumentRoot /www/subdomain/sub1
ServerName www.sub1.domain.tld
ServerPath /sub1/
RewriteEngine On
RewriteRule ^(/sub1/.*) /www/subdomain$1
# …
</VirtualHost>
<VirtualHost 172.20.30.40>
DocumentRoot /www/subdomain/sub2
ServerName www.sub2.domain.tld
ServerPath /sub2/
RewriteEngine On
RewriteRule ^(/sub2/.*) /www/subdomain$1
# …
</VirtualHost>
由于ServerPath指令的作用,发送到http://www.sub1.domain.tld/sub1/的请求总会被sub1-vhost所伺服。
如果客户端发送了正确的”Host:”头,发送到http://www.sub1.domain.tld/的请求只会被sub1-vhost所伺服。如果没有发送”Host:”头,客户端将会得到从主虚拟主机发送的信息页面。
请注意,这里还有一点小问题:如果客户端没有发送”Host:”头,发送到http://www.sub2.domain.tld/sub1/的请求还是会被sub1-vhost所伺服。
RewriteRule指令用以确保正确发送了”Host:”头的客户端可以任意使用这两种URL变量,比如说:使用或不使用URL前缀。
当使用了大量虚拟主机,而且每个主机又使用了不同的日志文件时,Apache可能会遭遇文件描述符(有时也称为文件句柄) 耗尽的困境。Apache使用的文件描述符总数如下:每个不同的错误日志文件一个、每个其他日志文件指令一个、再加10-20个作为内部使用。Unix操作系统限制了每个进程可以使用的文件描述符数量。典型上限是64个,但可以进行扩充,直至到达一个很大的硬件限制为止(hard-limit)。
尽管Apache会试着增大限制,但如果发生以下情况,则这个机制无法起作用:
1. 您的操作系统没有提供setrlimit()系统调用。
2. setrlimit(RLIMIT_NOFILE)调用无法在您的系统上正常工作(比如 Solaris 2.3)
3. 文件描述符的需求量已经超出了硬件的限制。
4. 您的操作系统对文件描述符作出了其他限制。比如说限制了stdio流只能使用256以下的文件描述符。(Solaris 2)
如果遇到了这样的问题,您可以这样解决:
* 减少日志文件的数量。不在<VirtualHost>配置段中指定日志文件,而是只在主日志文件中进行记录。(参见下述分解日志文件获得详情)
* 如果您的系统因上述第1条或第2条原因不能正常工作,可以在启动Apache之前,用类似下述的脚本增大文件描述符的限制:
#!/bin/sh
ulimit -S -n 100
exec httpd
分解日志文件
如果您想把多个虚拟主机的日志记录到同一个日志文件中,你可能会想事后把它们分开,以对不同的虚拟主机数据进行统计分析。您可用下述方法达到这个目的。
首先,您需要将虚拟主机的信息放入日志中。您可以用LogFormat指令和”%v”变量达到这个目的。在您的日志格式串的开头加入它们:
LogFormat “%v %h %l %u %t \”%r\” %>s %b” vhost
CustomLog logs/multiple_vhost_log vhost
这将用日志的普通格式来创建一个日志文件。但会在每条记录前加上正式的虚拟主机名(就是在ServerName指令中定义的那个)。(参见自定义日志格式以获取更多内容)
当您想将日志文件分开(每个虚拟主机一个日志文件)的时候,您可以使用split-logfile程序来完成这个工作。您将在Apache发行版的support目录中找到这个程序。
用如下命令来运行这个程序:
split-logfile < /logs/multiple_vhost_log
当这个程序在给予一个虚拟主机日志文件作为参数的情况下,会为日志文件中的每个虚拟主机建立一个文件。每个文件都以”主机名.log”这样的形式命名。
本文档描述如何使用Apache有效的架设大批量虚拟主机。
动机
如果你的配置文件httpd.conf中包含类似下面的许多<VirtualHost>段,并且其中的内容都大致相同的话,你应该会对这里所讲的技术感兴趣。比如:
NameVirtualHost 111.22.33.44
<VirtualHost 111.22.33.44>
ServerName www.customer-1.com
DocumentRoot /www/hosts/www.customer-1.com/docs
ScriptAlias /cgi-bin/ /www/hosts/www.customer-1.com/cgi-bin
</VirtualHost>
<VirtualHost 111.22.33.44>
ServerName www.customer-2.com
DocumentRoot /www/hosts/www.customer-2.com/docs
ScriptAlias /cgi-bin/ /www/hosts/www.customer-2.com/cgi-bin
</VirtualHost>
# 等 等 等 。。。
<VirtualHost 111.22.33.44>
ServerName www.customer-N.com
DocumentRoot /www/hosts/www.customer-N.com/docs
ScriptAlias /cgi-bin/ /www/hosts/www.customer-N.com/cgi-bin
</VirtualHost>
最基本的思想是用动态的机制来实现所有这些静态的<VirtualHost>配置段。这样做有许多优点:
1. 配置文件变小,使得Apache可以更快的启动,同时消耗更少的内存。
2. 添加一个虚拟主机,应该只是简单的在文件系统中创建合适的目录,以及配置相关的DNS信息,且无需重新启动Apache 。
主要的缺点是你无法针对每个虚拟主机使用不同的日志文件。然而,如果真的在配置有大量虚拟主机的服务器上记录不同的日志文件的话,很有可能会达到操作系统所允许的最大文件描述符的数量。更好的办法是把日志写到管道或者先入先出的栈,并启用其他的进程来分拣所得到的日志信息(同时也可以做一些历史纪录的统计等等)。
概述
一个虚拟主机由两部分来定义:一个是它的IP地址,还有一个是HTTP的”Host:”请求头。动态大量虚拟主机的技术,是基于自动在所要返回的文件路径中插入相关信息的想法实现的。使用mod_vhost_alias可以很容易的实现,但如果你的Apache版本低于1.3.6 ,则你必须使用mod_rewrite 。两者在默认情况下都不启用;要使用他们,必须在配置和编译Apache的阶段启用。
我们需要做很多”伪装”,才能使动态虚拟主机看起来像普通主机。最重要的一点是Apache使用虚拟主机名(ServerName)来生成自引用(self-referential)URL等信息。这是用ServerName指令来配置的,并且可以通过环境变量SERVER_NAME传递给CGI脚本。运行时实际使用的值是由UseCanonicalName指令的设置来控制的。当 UseCanonicalName Off 时,虚拟主机名(ServerName)取自请求中的”Host:”头。当 UseCanonicalName DNS 时,则通过DNS反解析虚拟主机的IP地址得到主机名。以前的做法是基于名称的动态虚拟主机,现在常用基于IP地址的虚拟主机。如果Apache无法判断虚拟主机名,则可能是没有”Host:”头或是DNS解析失败,这样种情况下,Apache将使用配置ServerName时所填写的主机名。
另一件需要”伪装”的事情是文档根目录(由DocumentRoot配置并可以通过DOCUMENT_ROOT环境变量为CGI脚本所使用)。在通常的配置方式下,这些设置信息由核心(core)模块在将URI映射到文件系统的时候使用,但是如果使用动态虚拟主机配置,这些信息将由另外一个使用不同于核心(core)模块将URI映射到文件系统的方式的模块(mod_vhost_alias或mod_rewrite)使用。这两个模块都不负责设置DOCUMENT_ROOT环境变量,所以如果CGI或SSI程序使用了DOCUMENT_ROOT环境变量,那么将得到错误的值。
简单的动态虚拟主机
这是httpd.conf文件中,完成和上文动机部分所提到的虚拟主机一样效果的配置方法,但这里采用了mod_vhost_alias模块:
# 从”Host:”头中取得主机名
UseCanonicalName Off
# 这种日志格式可以从第一个字段中提取出主机名
LogFormat “%V %h %l %u %t \”%r\” %s %b” vcommon
CustomLog logs/access_log vcommon
# 在返回请求的文件名路径中包含主机名
VirtualDocumentRoot /www/hosts/%0/docs
VirtualScriptAlias /www/hosts/%0/cgi-bin
将 UseCanonicalName Off 的配置改为 UseCanonicalName DNS 即可实现基于IP地址的虚拟主机。而在文件路径中所要插入的服务器名则通过虚拟主机的IP地址解析得到。
一个实际的个人主页系统
这里对上面的系统作了一点调整,便可作为ISP的个人主页服务器。我们使用了略微复杂的方法,从主机名(ServerName)中提取子字符串,并插入到文件路径中。在这个例子中www.user.isp.com的文档将在/home/user/中定位。并对所有虚拟主机使用单个cgi-bin目录。
# 所有之前的准备事项和上面一样,然后在文件路径中包含主机名
VirtualDocumentRoot /www/hosts/%2/docs
# 单个cgi-bin目录
ScriptAlias /cgi-bin/ /www/std-cgi/
更复杂的关于VirtualDocumentRoot的设置,可以查阅mod_vhost_alias文档。
在同一个服务器上架设多个主机的虚拟系统
更复杂的设置,应该使用Apache的<VirtualHost>容器来管理各种虚拟主机配置的作用域。例如,你可以用一个IP地址来给个人主页客户使用,同时用下面的配置提供给商业客户使用。自然的,这两者通过运用<VirtualHost>结合到一起。
UseCanonicalName Off
LogFormat “%V %h %l %u %t \”%r\” %s %b” vcommon
<Directory /www/commercial>
Options FollowSymLinks
AllowOverride All
</Directory>
<Directory /www/homepages>
Options FollowSymLinks
AllowOverride None
</Directory>
<VirtualHost 111.22.33.44>
ServerName www.commercial.isp.com
CustomLog logs/access_log.commercial vcommon
VirtualDocumentRoot /www/commercial/%0/docs
VirtualScriptAlias /www/commercial/%0/cgi-bin
</VirtualHost>
<VirtualHost 111.22.33.45>
ServerName www.homepages.isp.com
CustomLog logs/access_log.homepages vcommon
VirtualDocumentRoot /www/homepages/%0/docs
ScriptAlias /cgi-bin/ /www/std-cgi/
</VirtualHost>
更为有效的基于IP地址的虚拟主机
在第一个例子中说过,转为基于IP地址的虚拟主机设置很容易做到。但不幸的是,那种做法并不高效,因为这样会在每次处理请求时,需要查询DNS。通过在文件系统中包含 IP地址的做法可以避免这样的问题。这样一来,免去了和主机名的关联,在日志记录中也一样可以用IP来分离不同日志。Apache将不会为了确定主机名 (ServerName)而去做DNS查询。
# 从IP地址反解析得到主机名
UseCanonicalName DNS
# 在日志中包含IP地址,便于以后分拣
LogFormat “%A %h %l %u %t \”%r\” %s %b” vcommon
CustomLog logs/access_log vcommon
# 在文件路径中包含IP地址
VirtualDocumentRootIP /www/hosts/%0/docs
VirtualScriptAliasIP /www/hosts/%0/cgi-bin
使用老版本的Apache
上面的例子基于mod_vhost_alias ,但它是在版本1.3.6之后才出现的。如果你的版本比较老,可以通过使用mod_rewrite来达到相同的目的,如下所示。但只能是基于”Host:”头方式的虚拟主机。
此外还须注意日志方面的问题。Apache1.3.6是第一个支持”%V”日志格式指令的版本,在版本1.3.0-1.3.3中,”%v”选项做和”%V”一样的事情;而在版本1.3.4中没有等价指令。在所有的这些版本中,指令UseCanonicalName可以出现在.htaccess文件中,这意味着客户的设置可能会导致日志记录紊乱。所以最好的做法是使用”%{Host}i”指令,它可以直接记录”Host:”头;注意,这样可能在末尾包含”:port”,而使用”%V”则不会这样。
使用mod_rewrite实现简单的动态虚拟主机
这里的例子摘自httpd.conf ,效果等同于第一个例子中的情况。前半部分和上面的例子大致相似,只是为了向后兼容mod_rewrite作了适当修改;后半部分配置mod_rewrite来做实际的工作。
有些特别的地方需要注意:默认情况下,mod_rewrite在所有其他URI转换模块(mod_alias等)之前运行,所以如果使用这些模块的话,mod_rewrite必须作相应的调整。同时,我们还要为每个动态虚拟主机变些戏法,使之等效于ScriptAlias
# 从”Host:”头获取主机名
UseCanonicalName Off
# 可分拣的日志
LogFormat “%{Host}i %h %l %u %t \”%r\” %s %b” vcommon
CustomLog logs/access_log vcommon
<Directory /www/hosts>
# 这里需要ExecCGI ,因为我们不能强制CGI以与ScriptAlias相同的方式执行
Options FollowSymLinks ExecCGI
</Directory>
# 接下来是关键部分
RewriteEngine On
# 来自”Host:”头的ServerName ,可能大小写混杂
RewriteMap lowercase int:tolower
## 首先处理普通文档
# 允许变名/icons/起作用,其他变名类同
RewriteCond %{REQUEST_URI} !^/icons/
# 允许CGI
RewriteCond %{REQUEST_URI} !^/cgi-bin/
# 开始”变戏法”
RewriteRule ^/(.*)$ /www/hosts/${lowercase:%{SERVER_NAME}}/docs/$1
## 现在处理CGI(我们需要强制使用一个MIME类型)
RewriteCond %{REQUEST_URI} ^/cgi-bin/
RewriteRule ^/(.*)$ /www/hosts/${lowercase:%{SERVER_NAME}}/cgi-bin/$1 [T=application/x-httpd-cgi]
# ok 了!
使用mod_rewrite的个人主页系统
这里的配置完成和第二个例子相同的工作。
RewriteEngine on
RewriteMap lowercase int:tolower
# 允许CGI工作
RewriteCond %{REQUEST_URI} !^/cgi-bin/
# 检查hostname正确与否,之后才能使RewriteRule起作用
RewriteCond ${lowercase:%{SERVER_NAME}} ^www\.[a-z-]+\.isp\.com$
# 将虚拟主机名字连接到URI的开头
# [C]表明本次重写的结果将在下一个rewrite规则中使用
RewriteRule ^(.+) ${lowercase:%{SERVER_NAME}}$1 [C]
# 现在创建实际的文件名
RewriteRule ^www\.([a-z-]+)\.isp\.com/(.*) /home/$1/$2
# 定义全局CGI目录
ScriptAlias /cgi-bin/ /www/std-cgi/
使用独立的虚拟主机配置文件
这样的布局利用了mod_rewrite的高级特性,在独立的虚拟主机配置文件中转换。如此可以更为灵活,但需要较为复杂的设置。
vhost.map文件包含了类似下面的内容:
www.customer-1.com /www/customers/1
www.customer-2.com /www/customers/2
# …
www.customer-N.com /www/customers/N
http.conf包含了:
RewriteEngine on
RewriteMap lowercase int:tolower
# 定义映射文件
RewriteMap vhost txt:/www/conf/vhost.map
# 和上面的例子一样,处理别名
RewriteCond %{REQUEST_URI} !^/icons/
RewriteCond %{REQUEST_URI} !^/cgi-bin/
RewriteCond ${lowercase:%{SERVER_NAME}} ^(.+)$
# 这里做基于文件的重新映射
RewriteCond ${vhost:%1} ^(/.*)$
RewriteRule ^/(.*)$ %1/docs/$1
RewriteCond %{REQUEST_URI} ^/cgi-bin/
RewriteCond ${lowercase:%{SERVER_NAME}} ^(.+)$
RewriteCond ${vhost:%1} ^(/.*)$
RewriteRule ^/(.*)$ %1/cgi-bin/$1
虚拟主机部分的代码在Apache 1.3中进行了完全的重写。本文档试图详细解释Apache在接受到请求后如何确定使用哪一个虚拟主机进行伺服。在新的[b]NameVirtualHost[/b]指令的帮助下,虚拟主机的配置比1.3版以前更加简单和安全。
如果您只是想让它能够工作而不愿意进行深入理解,这里有一些示例。
解析配置文件
在<VirtualHost>配置段外有一个主服务器(main_server)段中包含着所有定义。其中有<VirtualHost>配置段中定义的叫做虚拟主机(vhost)的虚拟服务器。
Listen, ServerName, ServerPath, ServerAlias指令可以出现在一个服务器定义段的任何地方。而且每个指令都会覆盖前面出现的同样定义(在那个服务器配置中)。
主服务器段中Listen指令的默认值是80。主服务器段没有默认的ServerPath和ServerAlias指令值。ServerName的默认值是由服务器的IP地址推断而来。
主服务器的Listen指令有两个功能:其一是决定Apache将要绑定的网络端口;其二是在重定向中指定绝对URI将使用的端口号。
不象在主服务器里,虚拟服务器的端口不会影响到Apache的监听端口。
每个VirtualHost指令中的地址都可以附带一个可选的端口。如果没有进行特别的指定,这个端口默认为主服务器中最近的一个Listen指令指定的值。特殊的端口”*”表示匹配所有端口。所有这一系列地址(包括由DNS查询出的所有A记录)统称虚拟主机的地址集(address set)。
如果没有对一个特定的IP地址使用NameVirtualHost指令,那么第一个使用这个地址的虚拟主机将被视为基于IP的虚拟主机。IP地址也可以用通配符”*”表示。
如果使用了基于域名的虚拟主机,那么必须用NameVirtualHost指令为这个基于域名的虚拟主机指定IP地址集。换句话说,您必须在配置文件中通过NameVirtualHost指令指定包括主机名映射(CNAME)的IP地址。
可以使用很多NameVirtualHost指令来分别对应一套NameVirtualHost指令,但对于每个特定的”IP:port”对来说,只能使用一次NameVirtualHost指令。
NameVirtualHost和VirtualHost指令出现的顺序并不重要。只有对应同一个IP地址的VirtualHost指令的次序才是重要的。所以下面两例所起的作用是完全相同的:
(为了使您的配置文件更具可读性,我们推荐您使用左边的格式)
在解析完VirtualHost指令后,虚拟主机服务器将被赋予在它的VirtualHost指令中第一个名字对应的端口作为默认的Listen端口。
如果所有域名都指向同一个地址集的话,VirtualHost指令中的所有域名列表都将会得到和ServerAlias指令一样的处理(但不会被其他ServerAlias语句覆盖)。请注意,这个虚拟主机自带的Listen指令将不能影响到那个地址集的端口号。
在初始化的过程中,将会为每一个IP地址产生一个列表,并插入到一个散列表中。如果这个IP地址是用在一个NameVirtualHost指令中的,这个列表将会包含所有指定为这个IP地址的基于域名的虚拟主机。如果没有虚拟主机针对这个IP地址,那么NameVirtualHost指令将被忽略,并会在日志中记录一个错误信息。对于基于IP的虚拟主机而言,这个散列表中的列表为空。
因为使用了高效的散列算法,使得在请求到达的时候在其中查找IP地址的开销变得很小,或者根本不需考虑。而且这个表格还为只有最后一个八进制位不同的IP地址做了优化。
虚拟主机的每个变量都有初始值。特别是以下这些:
1. 如果虚拟主机没有ServerAdmin, ResourceConfig, AccessConfig, Timeout, KeepAliveTimeout, KeepAlive, MaxKeepAliveRequests, ReceiveBufferSize, SendBufferSize指令,那么将从主服务器继承它们的值。(也就是说,使用在主服务器中最后出现的设定值)。
2. 虚拟主机的默认目录权限将继承主服务器的设置(包括所有模块针对每个目录的配置信息)。
3. 虚拟主机将继承主服务器中每个模块针对主服务器的设置。
本质上,主服务器在建立每个虚拟主机的时候,充当了一个默认值或根基的角色。但这些存在于主服务器中的定义的位置是无关紧要的——主服务器的配置在与虚拟主机整合之前就已经解析过了。所以即使一个主服务器的配置出现在虚拟主机定义的后面,它也同样会影响到虚拟主机的配置。
如果没有定义主服务器中的ServerName ,那么将由运行这个httpd服务的机器的主机名来代替。我们将由DNS查找此ServerName返回的IP地址称为主服务器地址集(main_server address set)。
在没有定义ServerName的情况下,一个基于域名的虚拟主机默认采用定义虚拟主机时在VirtualHost指令中最先出现的地址。
所有使用了”_default_”通配符的虚拟主机将被赋予和主服务器相同的ServerName 。
虚拟主机匹配
服务器用下述方法来确定对一个特定的请求使用哪个虚拟主机:
散列表查找
当客户端第一次连接的时候,会从内部的IP散列表中查找客户端想要连接的IP地址。
如果查找失败(没有找到相应的IP地址),而所请求的端口又存在一个”_default_”虚拟主机,那么这个请求将会由这个虚拟主机来伺服。如果没有找到这样的”_default_”虚拟主机,那么这个请求将会由主服务器来伺服。
如果在散列表中没有找到IP地址,但存在一个”NameVirtualHost *”指令与所请求的端口号相匹配,那么将用这个虚拟主机来处理这个请求。
如果查找成功(找到了对应于这个IP地址的列表),下一步就是看我们要处理的是一个基于IP的虚拟主机还是一个基于域名的虚拟主机。
基于IP的虚拟主机
如果返回的列表中域名列表为空,那么我们处理的就是一个基于IP的虚拟主机,这个虚拟主机将会直接进行处理而不会有其他步骤。
基于域名的虚拟主机
如果返回的域名列表包含一个或多个虚拟主机的结构,那么我们处理的就是一个基于域名的虚拟主机。这个列表包含的虚拟主机的顺序与配置文件中相应VirtualHost指令出现的顺序是相同的。
这个列表中第一个虚拟主机(也就是在配置文件中第一个指定了这个IP地址的虚拟主机)对处理请求有着最高的优先级。所有对未知服务器名或没有”Host:”头的请求都将由它进行处理。
如果客户端在请求中提供了一个”Host:”头,那么将在列表中查找第一个ServerName或ServerAlias与其符合的虚拟主机,并将其用于伺服这个请求。尽管”Host:”头中可以包含端口号,但Apache还是会用收到请求的那个真实端口来进行匹配。
如果客户端提交了一个不包含”Host:”头的HTTP/1.0的请求,我们将无法确认客户端想要连接那个服务器。而如果存在一个ServerPath与客户端提交的请求中的URI相对应,那么列表中第一个符合条件的虚拟主机将用于伺服这个请求。
如果还是找不到对应的虚拟主机,那么这个请求将会由客户端连接的IP对应的列表中的第一个与请求的端口相同的虚拟主机来伺服(如前所述)。
持久连接
上述IP查找对一个特定的TCP/IP进程只执行一次。但在持久连接(KeepAlive)中,每个请求都会进行一次这样的查找过程。换句话说,一个客户端在一个持久连接中可以向位于不同的基于域名的虚拟主机的页面提出请求。
绝对URI
如果请求提交的URI是一个绝对URI,而其中的主机名和端口号又和主服务器或某个虚拟主机相符合,并且也与作为此请求提交对象的地址和端口相符,那么这个请求的类型/主机名/端口前缀将被抹除,仅留下相对URI为对应的主服务器或虚拟主机所伺服。如果不满足上述符合条件,这个URI将保留原样,而此请求将被作为一个代理请求处理。
备忘录
* 基于域名的虚拟主机和基于IP的虚拟主机之间互相不干扰。基于IP的虚拟主机只接受发送到它自身地址集的请求,而不接受其他IP地址。基于域名的虚拟主机也是一样,它们只接受NameVirtualHost指令定义的地址集的访问。
* 永远不会对一个基于IP的虚拟主机执行ServerAlias和ServerPath检查。
* 在配置文件中,基于域名的虚拟主机、基于IP的虚拟主机、”_default_”虚拟主机和NameVirtualHost指令出现的顺序并不重要。而对于某个指定的地址集来说,基于域名的虚拟主机的顺序是不能混淆的:在配置文件中较先出现的虚拟主机在相应的地址集中有较高的优先权。
* 出于安全性的考虑,在”Host:”头中出现的端口号将不用于匹配。Apache会一直使用客户端所连接的真实端口作为匹配。
* 如果一个ServerPath指令凑巧是后面出现的另外一个ServerPath指令的前缀,前者将用于匹配,而后者将被忽略。(这里讨论的是没有”Host:”头来将这两个情况分开的情况下)
* 如果有两个基于IP的虚拟主机使用了同一个地址,则在配置文件中首先出现的那个用于匹配。这种事情可能发生在你疏忽的时候。当服务器遇到这种情况的时候,会在日志文件中写入一个错误信息。
* 仅当没有其他虚拟主机符合客户端请求的IP地址和端口号时,”_default_”虚拟主机才会捕获这个请求。并且仅当”_default_”虚拟主机的端口号(默认值由您的Listen指定)与客户端发送请求的目的端口号相符时,这个请求才会被捕获。也可以使用通配符(例如:”_default_:*”)来捕获任何端口号的请求。这也同样适用于”NameVirtualHost *”的虚拟主机。
* 仅当客户端连接的目的IP地址和端口号没有指定而且不与任何一个虚拟主机(包括”_default_”虚拟主机)匹配的时候,才会用主服务器来伺服请求。换句话说,主服务器仅捕获没有指定IP地址和端口的请求(除非存在一个匹配端口的”_default_”虚拟主机)。
* 如果客户端连接到一个用于基于域名的虚拟主机使用的地址(和端口),比如说使用了NameVirtualHost指令,那么一个未知的或没有”Host:”头的请求就不会与”_default_”虚拟主机或是主服务器相匹配。
* 绝对不能在VirtualHost指令中使用DNS名称,否则您的服务器就会依赖DNS来进行启动。而且,如果您无法控制列表中所有的域,您将会面临安全威胁。您可以在这里获得关于这个问题和以下两个问题的更多详情。
* 应当为每个虚拟主机设定ServerName 。否则就会需要为每个虚拟主机进行DNS查询。
小技巧
作为DNS问题页面小技巧的附加,这里有些额外的技巧:
* 将所有主服务器的定义放在所有VirtualHost定义之前(为了增加可读性),否则会使得类似在虚拟主机旁边的定义影响到所有的虚拟主机这样的问题不容易发现。
* 将您配置中相应的NameVirtualHost和VirtualHost定义放到一起,以获得更好的可读性。
* 避免前一个ServerPaths是后一个ServerPaths的前缀。如果您无法避免这样的情况,您最好确保在您的配置文件中”长在前,短在后”(也就是说:”ServerPath/abc/def”应当出现在”ServerPath/abc”之前)。
来自:http://bbs.163jsp.com/posts/list/509.html;jsessionid=957967622CCF46F0D648E16BC4C0659E
原创文章,转载请注明: 转载自PT Ubuntu Blog
非常实用了!!!
根据里面的方法设置好,用了我两个小时!!学习了~~~