<-
Apache > HTTP 服务器 > 文档 > 版本 2.4 > 虚拟主机

虚拟主机示例

可用语言:  en  |  fr  |  ja  |  ko  |  tr 

本文档试图回答有关设置 虚拟主机 的常见问题。这些场景涉及通过 基于名称基于 IP 的虚拟主机在单个服务器上运行多个网站。

Support Apache!

另请参阅

top

在一个 IP 地址上运行多个基于名称的网站。

您的服务器有多个主机名解析到单个地址,并且您希望对 www.example.comwww.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 地址更改时无需更改即可正常工作。

top

在多个 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 处理。

top

在不同的 IP 地址(例如内部和外部地址)上提供相同的内容。

服务器机器有两个 IP 地址(192.168.1.1172.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 地址列表,这将导致服务器在所有地址上以相同的方式响应。

top

在不同的端口上运行不同的网站。

您有多个域指向同一个 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>
top

基于 IP 的虚拟主机

服务器有两个 IP 地址(172.20.30.40172.20.30.50),它们分别解析为名称 www.example.comwww.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)的请求将转到主服务器(如果有)。

top

混合端口和 IP 虚拟主机

服务器机器有两个 IP 地址(172.20.30.40172.20.30.50),它们分别解析为名称 www.example.comwww.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>
top

混合基于名称和基于 IP 的虚拟主机

虚拟主机参数中提到的任何从未出现在其他虚拟主机中的地址都是严格的基于 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>
top

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>
top

使用 _default_ 虚拟主机

所有端口的 _default_ 虚拟主机

捕获对任何未指定 IP 地址和端口的所有请求,,任何未用于任何其他虚拟主机的地址/端口组合。

<VirtualHost _default_:*>
    DocumentRoot "/www/default"
</VirtualHost>

使用带有通配符端口的此类默认虚拟主机实际上会阻止任何请求转到主服务器。

默认虚拟主机永远不会处理发送到用于基于名称的虚拟主机的地址/端口的请求。如果请求包含未知或没有 Host: 标头,它始终由主基于名称的虚拟主机处理(配置文件中第一个出现在该地址/端口的虚拟主机)。

您可以使用 AliasMatchRewriteRule 将任何请求重写到单个信息页面(或脚本)。

不同端口的 _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_

top

将基于名称的虚拟主机迁移到基于 IP 的虚拟主机

具有主机名 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 的虚拟主机)和旧地址(作为基于名称的虚拟主机)访问虚拟主机。

top

使用 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 前缀。

可用语言:  en  |  fr  |  ja  |  ko  |  tr 

top

评论

注意
这不是一个问答部分。此处放置的评论应针对改进文档或服务器的建议,如果它们被实施或被认为无效/不相关,可能会被我们的版主删除。有关如何管理 Apache HTTP Server 的问题应发送到我们的 IRC 频道 #httpd(在 Libera.chat 上)或发送到我们的 邮件列表