apache / 2.4 / reference / vhosts-mass.html

动态配置的批量虚拟主机

本文档介绍了如何通过 Apache HTTP Server 有效地为任意数量的虚拟主机提供服务。 separate document讨论使用mod_rewrite创建动态大量虚拟主机。

Motivation

如果您的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>块。这具有许多优点:

  • 您的配置文件较小,因此 Apache 启动速度更快,并且使用的内存更少。也许更重要的是,较小的配置更易于维护,并且留出更少的出错空间。

  • 添加虚拟主机仅需在文件系统中创建适当的目录,并在 DNS 中创建条目即可-无需重新配置或重新启动 Apache。

主要缺点是每个虚拟主机不能有不同的日志文件。但是,如果您有许多虚拟主机,则由于所需的文件 Descriptors 数量,这样做还是个坏主意。最好使用登录到管道或 fifo,并安排另一端的过程将每个虚拟主机的日志文件拆分为一个。可以在split-logfileUtil 中找到这种过程的一个示例。

Overview

虚拟主机由两条信息定义:其 IP 地址和 HTTP 请求中Host:Headers 的内容。此处使用的动态批量虚拟主机技术基于自动将此信息插入用于满足请求的文件的路径名中。通过将mod_vhost_alias与 Apache httpd 一起使用,可以很容易地做到这一点。或者,可以使用 mod_rewrite

默认情况下,这两个模块均处于禁用状态。如果要使用此技术,则在配置和构建 Apache httpd 时必须启用其中之一。

为了使动态虚拟主机看起来像普通主机,需要从请求中确定几件事。最重要的是服务器名称,服务器使用它来生成自我引用的 URL 等。它使用ServerName指令进行配置,并且可以通过SERVER_NAME环境变量供 CGI 使用。运行时使用的实际值由UseCanonicalName设置控制。使用UseCanonicalName Off,服务器名称取自请求中Host:头的内容。使用UseCanonicalName DNS,它是从虚拟主机的 IP 地址的反向 DNS 查找获得的。前一种设置用于基于名称的动态虚拟主机,而后一种设置用于基于 IP 的主机。如果 httpd 由于没有Host:Headers 而无法计算出服务器名称,或者 DNS 查找失败,则使用ServerName配置的值。

要确定的另一件事是文档根目录(使用DocumentRoot配置,并且可以通过DOCUMENT_ROOT环境变量用于 CGI 脚本)。在正常配置中,核心模块在将 URI Map 到文件名时会使用此功能,但是当服务器配置为进行动态虚拟主机时,该作业必须由另一个模块(mod_vhost_aliasmod_rewrite)接管,而另一个模块则有所不同 Map 的方式。这两个模块都不负责设置DOCUMENT_ROOT环境变量,因此,如果任何 CGI 或 SSI 文档都使用它,它们将获得误导的值。

具有 mod_vhost_alias 的动态虚拟主机

httpd.conf的摘录使用mod_vhost_alias实现了上面Motivation部分中概述的虚拟主机安排。

# 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:Headers 中所示。

有关更多用法示例,请参见mod_vhost_alias文档。

简化的动态虚拟主机

这是对上述系统的调整,专门针对 ISP 的网络托管服务器。使用%2,我们可以选择服务器名的子字符串以在文件名中使用,例如,在/home/user/www中可以找到www.user.example.com的文档。它使用单个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>指令来控制各种虚拟主机配置的范围。例如,通过以下设置,您可以为普通 Client 的主页提供一个 IP 地址,为商业 Client 提供一个 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>

Note

如果第一个 VirtualHost 块包含ServerName指令,则将使用相关 IP 的反向 DNS。如果这不是您希望使用的服务器名称,则可以添加虚假条目(例如ServerName none.example.com)来解决此问题。

更高效的基于 IP 的虚拟主机

建议进行配置更改以将第一个例子转换为基于 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 的虚拟主机

大规模虚拟主机也可以使用mod_rewrite来完成,或者使用简单的RewriteRule指令,或者使用更复杂的技术,例如在外部存储 vhost 定义并通过RewriteMap访问它们。在rewrite documentation中讨论了这些技术。

使用 mod_macro 的虚拟主机

动态生成的虚拟主机的另一个选项是mod_macro,您可以使用它创建一个虚拟主机模板,并为多个主机名调用它。模块文档的“用法”部分提供了一个示例。