虚拟主机匹配的深入讨论

本文档试图确切解释 Apache HTTP Server 在确定服务于哪个虚拟主机的请求时的功能。

大多数用户应阅读有关基于名称的虚拟主机与基于 IP 的虚拟主机的信息,以决定他们要使用的类型,然后阅读有关name-basedIP-based虚拟主机的更多信息,然后查看some examples

如果您想了解所有详细信息,则可以返回此页面。

Configuration File

有一个“主服务器”,它由出现在<VirtualHost>部分之外的所有定义组成。

有称为_vhosts *的虚拟服务器,它们由<VirtualHost>部分定义。

每个VirtualHost指令都包含一个或多个地址和可选端口。

可以使用主机名代替虚拟主机定义中的 IP 地址,但是在启动时会解析它们,如果任何名称解析失败,这些虚拟主机定义将被忽略。因此,不建议这样做。

可以将地址指定为*,如果没有其他虚拟主机具有在其上接收到请求的显式地址,则该地址将与请求匹配。

VirtualHost指令中显示的地址可以具有可选端口。如果未指定端口,则将其视为通配符端口,也可以使用*明确指出。通配符端口与任何端口匹配。

(在VirtualHost指令中指定的端口号不会影响 Apache 侦听的端口号,它们仅控制选择哪个VirtualHost来处理请求.使用Listen指令可控制服务器侦听的地址和端口。)

整个地址集(包括来自 DNS 查找的多个结果)统称为虚拟主机的地址集

只要在多个虚拟主机中列出了 IP 地址和端口组合的最具体匹配项,Apache 就会根据 Client 端提供的 HTTP HostHeaders 自动进行区分。

ServerName指令可以出现在服务器定义内的任何位置。但是,每个外观都将覆盖先前的外观(在该服务器内)。如果未指定ServerName,则服务器尝试从服务器的 IP 地址推导出它。

给定 IP:端口对的配置文件中第一个基于名称的虚拟主机很重要,因为它用于该地址和端口上接收到的所有请求,而该 IP:端口对没有其他虚拟主机具有匹配的 ServerName 或 ServerAlias。如果服务器不支持服务器名称指示,则还用于所有 SSL 连接。

VirtualHost指令中名称的完整列表被视为(非通配符)ServerAlias(但不会被任何ServerAlias语句覆盖)。

为每个虚拟主机设置各种默认值。特别是:

  • 如果虚拟主机没有ServerAdminTimeoutKeepAliveTimeoutKeepAliveMaxKeepAliveRequestsReceiveBufferSizeSendBufferSize指令,则各自的值将从主服务器继承。 (也就是说,继承自主服务器中该值的最终设置.)

  • 定义虚拟主机的默认目录权限的“查找默认值”与主服务器的权限合并在一起。这包括任何模块的任何按目录的配置信息。

  • 主服务器中每个模块的每服务器配置都合并到 vhost 服务器中。

本质上,主服务器被视为构建每个虚拟主机的“默认值”或“基础”。但是,这些主服务器定义在 config 文件中的位置基本上无关紧要-当最终合并发生时,已经解析了主服务器的整个配置。因此,即使主服务器定义出现在虚拟主机定义之后,它也可能会影响虚拟主机定义。

如果此时主服务器上没有ServerName,则使用运行httpd的计算机的主机名。我们将“主服务器地址集”称为由 DNS 查询在主服务器ServerName上返回的 IP 地址。

对于任何未定义的ServerName字段,基于名称的虚拟主机默认为在定义虚拟主机的VirtualHost语句中首先指定的地址。

任何包含魔术_default_通配符的虚拟主机都将与主服务器获得相同的ServerName

虚拟主机匹配

服务器确定要用于请求的虚拟主机,如下所示:

IP 地址查询

当首次在某个地址和端口上接收到连接时,服务器将查找具有相同 IP 地址和端口的所有VirtualHost定义。

如果地址和端口不完全匹配,则考虑通配符(*)。

如果未找到匹配项,则该请求由主服务器处理。

如果 IP 地址有VirtualHost个定义,则下一步是确定我们是否必须处理基于 IP 的虚拟主机或基于名称的虚拟主机。

IP-based vhost

如果恰好有一个VirtualHost指令列出了确定为最匹配的 IP 地址和端口组合,则不会执行进一步的操作,并且会从匹配的虚拟主机为请求提供服务。

Name-based vhost

如果有多个VirtualHost指令列出了确定为最匹配的 IP 地址和端口组合,则其余步骤中的“列表”指的是匹配的虚拟主机的列表,按照它们在配置文件中的 Sequences 排列。

如果连接使用 SSL,则服务器支持服务器名称指示,并且 SSL Client 端握手包括带有请求的主机名的 TLS 扩展,则该主机名将在下面使用,就像在非 SSL 连接上使用Host:Headers 一样。否则,地址匹配的第一个基于名称的虚拟主机将用于 SSL 连接。这很重要,因为虚拟主机确定服务器将使用哪个证书进行连接。

如果请求包含Host:头字段,则在列表中搜索具有匹配的ServerNameServerAlias的第一个虚拟主机,并从该虚拟主机提供请求。 Host:Headers 字段可以包含端口号,但是 Apache 始终忽略它,并与 Client 端向其发送请求的实际端口相匹配。

配置文件中具有指定 IP 地址的第一个虚拟主机具有最高优先级,并捕获对未知服务器名称的任何请求,或捕获没有Host:头字段的请求(例如 HTTP/1.0 请求)。

Persistent connections

上面描述的* IP 查找仅针对特定的 TCP/IP 会话一次,而名称查找仅在 KeepAlive /持久连接期间对每个*请求中都进行。换句话说,Client 端可以在单个持久连接期间从不同的基于名称的虚拟主机请求页面。

Absolute URI

如果来自请求的 URI 是绝对 URI,并且其主机名和端口与主服务器匹配,或者已配置的虚拟主机之一与 Client 端向其发送请求的地址和端口匹配,则方案/主机名/端口前缀被剥离,其余的相对 URI 由相应的主服务器或虚拟主机提供。如果不匹配,则 URI 保持不变,并且该请求被视为代理请求。

Observations

  • 基于名称的虚拟主机是在服务器选择最匹配的基于 IP 的虚拟主机之后应用的过程。

  • 如果您不关心 Client 端连接到的 IP 地址,请使用“ *”作为每个虚拟主机的地址,并且基于名称的虚拟主机将应用于所有已配置的虚拟主机。

  • 永远不会对基于 IP 的虚拟主机执行ServerNameServerAlias检查。

  • 仅特定地址集的基于名称的虚拟主机的 Sequences 很重要。在配置文件中排在首位的基于名称的虚拟主机具有最高的优先级为其对应的地址集。

  • 匹配过程中永远不会使用Host:Headers 字段中的任何端口。 Apache 始终使用 Client 端向其发送请求的实际端口。

  • 如果两个虚拟主机具有一个公共地址,则这些公共地址将隐式充当基于名称的虚拟主机。从 2.3.11 开始,这是新行为。

  • 仅当 Client 端连接的 IP 地址和端口号与任何虚拟主机(包括*虚拟主机)都不匹配时,才使用主服务器来处理请求。换句话说,主服务器仅捕获对未指定地址/端口组合的请求(除非存在与该端口匹配的_default_虚拟主机)。

  • 您永远不要在VirtualHost指令中指定 DNS 名称,因为它会强制您的服务器依靠 DNS 进行引导。此外,如果您不控制列出的所有域的 DNS,则会构成安全威胁。此主题和下两个主题有more information个。

  • 始终应为每个虚拟主机设置ServerName。否则,每个虚拟主机都需要进行 DNS 查找。

Tips

除了DNS Issues页上的提示之外,还有一些其他提示:

  • 将所有主服务器定义放在任何VirtualHost定义之前。 (这是为了提高配置的可读性-配置后合并过程使得不清楚虚拟主机周围混合的定义可能会影响所有虚拟主机.)