Apache HTTP Server 版本 2.4
本文档介绍如何使用 Apache HTTP Server 高效地为任意数量的虚拟主机提供服务。一篇单独的文档讨论了使用mod_rewrite
创建动态大量虚拟主机。
如果您 httpd.conf
文件包含许多实质上相同的 <VirtualHost>
部分,那么这里描述的技术将很有用,例如
<VirtualHost 111.22.33.44> ServerName customer-1.example.com DocumentRoot "/www/hosts/customer-1.example.com/docs" ScriptAlias "/cgi-bin/" "/www/hosts/customer-1.example.com/cgi-bin" </VirtualHost> <VirtualHost 111.22.33.44> ServerName customer-2.example.com DocumentRoot "/www/hosts/customer-2.example.com/docs" ScriptAlias "/cgi-bin/" "/www/hosts/customer-2.example.com/cgi-bin" </VirtualHost> <VirtualHost 111.22.33.44> ServerName customer-N.example.com DocumentRoot "/www/hosts/customer-N.example.com/docs" ScriptAlias "/cgi-bin/" "/www/hosts/customer-N.example.com/cgi-bin" </VirtualHost>
我们希望用一种动态生成这些 <VirtualHost>
块的机制来替换它们。这有许多优点
主要缺点是您不能为每个虚拟主机设置不同的日志文件;但是,如果您有许多虚拟主机,这样做可能不是一个好主意,因为所需的 文件描述符数量。最好将日志记录到管道或 FIFO,并安排另一端的过程将日志文件拆分为每个虚拟主机一个。在split-logfile 实用程序中可以找到此类过程的一个示例。
虚拟主机由两部分信息定义:它的 IP 地址和 HTTP 请求中 Host:
标头的内容。这里使用的动态大量虚拟主机技术基于自动将此信息插入用于满足请求的文件的路径名中。这可以通过使用 Apache httpd 的mod_vhost_alias
最轻松地完成。或者,可以使用 mod_rewrite。
这两个模块默认情况下都是禁用的;如果您想使用此技术,则必须在配置和构建 Apache httpd 时启用其中一个。
为了使动态虚拟主机看起来像一个正常的虚拟主机,需要从请求中确定一些事情。最重要的是服务器名称,服务器使用它来生成自引用 URL 等。它通过 ServerName
指令配置,并且可以通过 SERVER_NAME
环境变量提供给 CGI。运行时使用的实际值由UseCanonicalName
设置控制。使用 UseCanonicalName Off
,服务器名称取自请求中 Host:
标头的内容。使用 UseCanonicalName DNS
,它取自虚拟主机 IP 地址的反向 DNS 查找。前者用于基于名称的动态虚拟主机,后者用于基于 IP 的主机。如果 httpd 由于没有 Host:
标头或 DNS 查找失败而无法确定服务器名称,则使用 ServerName
配置的值。
另一件事是确定文档根目录(通过 DocumentRoot
配置,并通过 DOCUMENT_ROOT
环境变量提供给 CGI 脚本)。在正常配置中,这由核心模块在将 URI 映射到文件名时使用,但是当服务器配置为执行动态虚拟主机时,该任务必须由另一个模块(mod_vhost_alias
或 mod_rewrite
)接管,该模块有不同的映射方式。这两个模块都不负责设置 DOCUMENT_ROOT
环境变量,因此如果任何 CGI 或 SSI 文档使用它,它们将获得一个误导性的值。
来自 httpd.conf
的此摘录使用 mod_vhost_alias
实现上面动机部分中概述的虚拟主机安排。
# get the server name from the Host: header UseCanonicalName Off # this log format can be split per-virtual-host based on the first field # using the split-logfile utility. LogFormat "%V %h %l %u %t \"%r\" %s %b" vcommon CustomLog "logs/access_log" vcommon # include the server name in the filenames used to satisfy requests VirtualDocumentRoot "/www/hosts/%0/docs" VirtualScriptAlias "/www/hosts/%0/cgi-bin"
此配置可以通过将 UseCanonicalName Off
更改为 UseCanonicalName DNS
转换为基于 IP 的虚拟主机解决方案。插入文件名的服务器名称然后从虚拟主机的 IP 地址派生。变量 %0
引用请求的服务器名称,如 Host:
标头中所示。
有关更多使用示例,请参阅mod_vhost_alias
文档。
这是对上述系统的调整,专门针对 ISP 的网站托管服务器。使用 %2
,我们可以选择服务器名称的子字符串以在文件名中使用,以便例如,www.user.example.com
的文档位于 /home/user/www
中。它使用单个 cgi-bin
目录,而不是每个虚拟主机一个。
UseCanonicalName Off LogFormat "%V %h %l %u %t \"%r\" %s %b" vcommon CustomLog "logs/access_log" vcommon # include part of the server name in the filenames VirtualDocumentRoot "/home/%2/www" # single cgi-bin directory ScriptAlias "/cgi-bin/" "/www/std-cgi/"
在mod_vhost_alias
文档中,有更多复杂的 VirtualDocumentRoot
设置的示例。
对于更复杂的设置,您可以使用 httpd 的正常 <VirtualHost>
指令来控制各种虚拟主机配置的范围。例如,您可以为一般客户的主页设置一个 IP 地址,为商业客户设置另一个 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.example.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.example.com CustomLog "logs/access_log.homepages" vcommon VirtualDocumentRoot "/www/homepages/%0/docs" ScriptAlias "/cgi-bin/" "/www/std-cgi/" </VirtualHost>
如果第一个 VirtualHost 块不包含ServerName
指令,则将使用相关 IP 的反向 DNS。如果这不是您要使用的服务器名称,则可以添加一个虚假条目(例如 ServerName none.example.com
)来解决此问题。
将第一个示例转换为基于 IP 的虚拟主机设置的建议配置更改会导致效率低下。每个请求都需要进行新的 DNS 查找。为了避免这种开销,可以将文件系统安排为对应于 IP 地址,而不是主机名,从而无需进行 DNS 查找。日志记录也必须调整以适应此系统。
# get the server name from the reverse DNS of the IP address UseCanonicalName DNS # include the IP address in the logs so they may be split LogFormat "%A %h %l %u %t \"%r\" %s %b" vcommon CustomLog "logs/access_log" vcommon # include the IP address in the filenames VirtualDocumentRootIP "/www/hosts/%0/docs" VirtualScriptAliasIP "/www/hosts/%0/cgi-bin"
也可以使用 mod_rewrite
实现大量虚拟主机,无论是使用简单的 RewriteRule
指令,还是使用更复杂的技术,例如将虚拟主机定义存储在外部并通过 RewriteMap
访问它们。这些技术在rewrite 文档中进行了讨论。
动态生成虚拟主机的另一个选择是 mod_macro
,您可以使用它创建虚拟主机模板,并为多个主机名调用它。模块文档的用法部分提供了此示例。