Apache HTTP Server 版本 2.4
Virtual_host
和 mod_proxy 一起使用_default_
虚拟主机ServerPath
指令您的服务器有多个主机名解析到单个地址,并且您希望对 www.example.com
和 www.example.org
进行不同的响应。
在您的 Apache 服务器上创建虚拟主机配置不会神奇地为这些主机名创建 DNS 条目。您必须在 DNS 中拥有解析到您的 IP 地址的名称,否则其他人将无法看到您的网站。您可以在 hosts
文件中放置条目以进行本地测试,但这仅适用于具有这些 hosts
条目的机器。
# Ensure that Apache listens on port 80 Listen 80 <VirtualHost *:80> DocumentRoot "/www/example1" ServerName www.example.com # Other directives here </VirtualHost> <VirtualHost *:80> DocumentRoot "/www/example2" ServerName www.example.org # Other directives here </VirtualHost>
星号匹配所有地址,因此主服务器不处理任何请求。由于 ServerName www.example.com
的虚拟主机在配置文件中排在第一位,因此它具有最高优先级,可以被视为默认或主服务器。这意味着,如果收到与任何指定的 ServerName
指令不匹配的请求,它将由第一个 <VirtualHost>
处理。
上面的配置是您几乎在所有基于名称的虚拟主机情况下都想要使用的配置。实际上,此配置唯一无法处理的情况是,当您根据不同的 IP 地址或端口提供不同的内容时。
您可以用系统上的特定 IP 地址替换 *
。此类虚拟主机仅用于接收连接到指定 IP 地址的 HTTP 请求。
但是,在 IP 地址不可预测的系统上使用 *
也很有用 - 例如,如果您在 ISP 处拥有动态 IP 地址,并且您正在使用某种动态 DNS 解决方案。由于 *
匹配任何 IP 地址,因此此配置在您的 IP 地址更改时无需更改即可正常工作。
此处讨论的任何技术都可以扩展到任意数量的 IP 地址。
服务器有两个 IP 地址。在一个(172.20.30.40
)上,我们将提供“主”服务器 server.example.com
,而在另一个(172.20.30.50
)上,我们将提供两个或多个虚拟主机。
Listen 80 # This is the "main" server running on 172.20.30.40 ServerName server.example.com DocumentRoot "/www/mainserver" <VirtualHost 172.20.30.50> DocumentRoot "/www/example1" ServerName www.example.com # Other directives here ... </VirtualHost> <VirtualHost 172.20.30.50> DocumentRoot "/www/example2" ServerName www.example.org # Other directives here ... </VirtualHost>
任何对除 172.20.30.50
之外的地址的请求都将由主服务器处理。对 172.20.30.50
的请求,如果主机名未知或没有 Host:
标头,将由 www.example.com
处理。
服务器机器有两个 IP 地址(192.168.1.1
和 172.20.30.40
)。该机器位于内部(内联网)网络和外部(互联网)网络之间。在网络外部,名称 server.example.com
解析为外部地址(172.20.30.40
),但在网络内部,相同的名称解析为内部地址(192.168.1.1
)。
可以使用单个 <VirtualHost>
部分使服务器能够以相同的内容响应内部和外部请求。
<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,并且还希望提供多个端口。下面的示例说明了名称匹配是在确定最佳匹配的 IP 地址和端口组合之后进行的。
Listen 80 Listen 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 地址(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 地址(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 的虚拟主机。
Listen 80 <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.example.net </VirtualHost> # IP-based <VirtualHost 172.20.30.50> DocumentRoot "/www/example4" ServerName www.example.edu </VirtualHost> <VirtualHost 172.20.30.60> DocumentRoot "/www/example5" ServerName www.example.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>
使用带有通配符端口的此类默认虚拟主机实际上会阻止任何请求转到主服务器。
默认虚拟主机永远不会处理发送到用于基于名称的虚拟主机的地址/端口的请求。如果请求包含未知或没有 Host:
标头,它始终由主基于名称的虚拟主机处理(配置文件中第一个出现在该地址/端口的虚拟主机)。
您可以使用 AliasMatch
或 RewriteRule
将任何请求重写到单个信息页面(或脚本)。
_default_
虚拟主机与设置 1 相同,但服务器监听多个端口,并且我们希望为端口 80 使用第二个 _default_
虚拟主机。
<VirtualHost _default_:80> DocumentRoot "/www/default80" # ... </VirtualHost> <VirtualHost _default_:*> DocumentRoot "/www/default" # ... </VirtualHost>
端口 80 的默认虚拟主机(必须出现在任何带有通配符端口的默认虚拟主机之前)捕获发送到未指定 IP 地址的所有请求。主服务器永远不会用于处理请求。
_default_
虚拟主机我们希望为端口 80 设置一个默认虚拟主机,但没有其他默认虚拟主机。
<VirtualHost _default_:80> DocumentRoot "/www/default" ... </VirtualHost>
对端口 80 上未指定地址的请求将由默认虚拟主机处理。对未指定地址和端口的任何其他请求将由主服务器处理。
在虚拟主机声明中使用 *
的优先级将高于 _default_
。
具有主机名 www.example.org
的基于名称的虚拟主机(来自我们的 基于名称 示例,设置 2)应该获得自己的 IP 地址。为了避免名称服务器或代理缓存基于名称的虚拟主机的旧 IP 地址而导致的问题,我们希望在迁移阶段提供两种变体。
解决方案很简单,因为我们可以简单地将新 IP 地址(172.20.30.50
)添加到 VirtualHost
指令中。
Listen 80 ServerName www.example.com DocumentRoot "/www/example1" <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 前缀的链接的单个页面。
<VirtualHost 172.20.30.40> # primary vhost 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
指令,对 URL http://www.sub1.domain.tld/sub1/
的请求始终由 sub1-虚拟主机处理。
对 URL http://www.sub1.domain.tld/
的请求仅在客户端发送了正确的 Host:
标头时才由 sub1-虚拟主机处理。如果没有发送 Host:
标头,客户端将从主主机获取信息页面。
请注意,有一个奇怪之处:如果客户端没有发送 Host:
标头,对 http://www.sub2.domain.tld/sub1/
的请求也将由 sub1-虚拟主机处理。
使用 RewriteRule
指令确保发送了正确 Host:
标头的客户端可以使用两种 URL 变体,即,带有或不带有 URL 前缀。