虚拟主机样例(VirtualHost)
本文档尝试回答有关设置虚拟主机的常见问题。这些方案涉及通过基于名称或基于IP的虚拟主机在单个服务器上运行的多个网站。
在单个IP地址上运行多个基于名称的网站。
您的服务器具有多个解析为单个地址的主机名,并且您希望对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>
星号匹配所有地址,因此主服务器不处理任何请求。由于虚拟主机with ServerName www.example.com
是配置文件中的第一名,因此它具有最高的优先级,可以被视为默认服务器或主服务器。这意味着,如果接收到与指定ServerName
指令之一不匹配的请求,则此first将为其提供服务<VirtualHost>
。
上面的配置是您几乎希望在所有基于名称的虚拟主机情况下使用的配置。实际上,此配置唯一不起作用的是基于不同的IP地址或端口提供不同的内容时。
注意
您可以用系统*
上的特定IP地址替换。此类虚拟主机仅用于连接到指定IP地址时收到的HTTP请求。
但是,*
在IP地址不可预测的系统上使用还很有用-例如,如果您的ISP具有动态IP地址,并且您正在使用各种动态DNS解决方案。由于*
匹配任何IP地址,因此只要您的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地址(例如内部和外部地址)上提供相同的内容。
服务器计算机有两个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的虚拟主机
该服务器有两个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的混合虚拟主机
服务器计算机有两个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的混合虚拟主机
在虚拟主机的参数中提到的从未出现在其他虚拟主机中的任何地址都是严格基于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相同,但是服务器侦听多个端口,并且我们想_default_
为端口80 使用第二个虚拟主机。
<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_
。
将基于名称的虚拟主机迁移到基于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的虚拟主机)和旧地址(作为基于名称的虚拟主机)访问该虚拟主机。
使用ServerPath
指令
我们有一台带有两个基于名称的虚拟主机的服务器。为了匹配正确的虚拟主机,客户端必须发送正确的Host:
标头。旧的HTTP / 1.0客户端不会发送这样的标头,并且Apache不知道客户端试图到达哪个虚拟主机(并服务于来自主要虚拟主机的请求)。为了提供尽可能多的向后兼容性,我们创建了一个主虚拟主机,该主机返回一个页面,该页面包含带有指向基于名称的虚拟主机的URL前缀的链接。
<VirtualHost 172.20.30.40> # primary vhost DocumentRoot "/www/subdomain" RewriteEngine On RewriteRule "." "/www/subdomain/index" # ... </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的虚拟主机服务。如果客户端发送了正确的标头,则仅从sub1-vhost
提供对URL的请求。如果未发送头,则客户端从主主机获取信息页面。http://www.sub1.domain.tld/
Host:
Host:
请注意,有一个奇怪的地方:http://www.sub2.domain.tld/sub1/
如果客户端未发送Host:
标头,sub1-vhost也会向发送请求。
该RewriteRule
指令用于确保发出了一个正确的客户端Host:
头可同时使用网址变体,即,有或没有网址前缀。