Apache Web服务器可以在SAME服务器上托管多个网站。每个网站不需要单独的服务器机器和apache软件。这可以使用虚拟主机或VHost的概念来实现。
要在Web服务器上托管的任何域(网站应用)都将在apache配置文件中具有单独的条目。
Apache虚拟主机类型有两种 -
基于名称的虚拟主机用于在单个IP地址上托管多个虚拟站点。
要配置基于名称的虚拟主机,需要设置要在其上接收所有所需网站的Apache请求的IP地址。可以通过apache配置中的NameVirutalHost指令(即/etc/httpd/conf/httpd.conf
文件)执行此操作。如下所示 -
NameVirtualHost *:80 <VirtualHost 192.168.0.108:80> ServerAdmin webmaster@zyiz.net DocumentRoot /var/www/html/example1_com_dir ServerName www.example1.com </VirtualHost> <VirtualHost 192.168.0.108:80> ServerAdmin admin@zyiz.net DocumentRoot /var/www/html/example2_com_dir ServerName www.example2.com </VirtualHost>
您可以根据需要添加任意数量的虚拟主机。需要使用以下命令检查Web配置文件是否有配置错误:
[root@115 conf.d]# httpd -t Syntax error on line 978 of /etc/httpd/conf/httpd.conf: Invalid command '*', perhaps misspelled or defined by a module not included in the server configuration
如上面显示的结果可以发现,配置文件存在语法配置错误,这时需要根据提示修改配置文件。直到没有错误提示为止。当配置文件有错误时,Apache是不能启动的,这点需要注意。
要设置基于IP的虚拟主机,需要在服务器上配置多个IP地址。因此,vhost apache的数量取决于服务器上配置的IP地址数量。如果您的服务器有10个IP地址,则可以创建10个基于IP的虚拟主机。
在上图中,两个网站example1.com
和example2.com
分配了不同的IP并使用基于IP的虚拟主机。
Listen 192.168.0.100:80 <VirtualHost 192.168.10.108:80> ServerAdmin webmaster@example1.com DocumentRoot /var/www/html/example1_com_dir ServerName www.example1.com </VirtualHost> <VirtualHost 192.168.10.109:80> ServerAdmin admin@example2.com DocumentRoot /var/www/html/example1_com_dir ServerName www.example2.com </VirtualHost>
这一小节中将列出有关设置虚拟主机的常见问题。这些方案涉及通过基于名称或基于IP的虚拟主机在单个服务器上运行的多个网站。
如果服务器有多个主机名可以解析为单个地址,您希望对www.example.com
和www.example.org
做出不同的响应。
在Apache服务器上创建虚拟主机配置不会神奇地导致为这些主机名创建DNS条目。您必须拥有DNS中的名称,解析为您的IP地址,否则其他人都无法访问您的网站。可以将条目放在
hosts
文件中以进行本地测试,但这仅适用于具有这些主机条目的计算机。
# Ensure that Apache listens on port 80 Listen 80 <VirtualHost *:80> DocumentRoot "/var/www/example1" ServerName www.example.com # Other directives here </VirtualHost> <VirtualHost *:80> DocumentRoot "/var/www/example2" ServerName www.example.org # Other directives here </VirtualHost>
服务器有两个(或更多个)IP地址。一个IP地址是:172.20.30.40,我们将服务于“主”服务器server.example.com
,另一个IP地址是: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
以外的地址的任何请求都将从主服务器提供。将向www.example.com
提供对172.20.30.50
的请求,其中包含未知主机名或无Host:标头。
服务器计算机有两个IP地址(192.168.1.1
和172.20.30.40
)。机器位于内部(Intranet)网络和外部(Internet)网络之间。在网络外部,名称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>
假设您有多个域转到同一个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>
以下示例允许前端计算机将虚拟主机代理到另一台计算机上运行的服务器。在该示例中,在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 vhosts适用于所有端口
捕获对任何未指定的IP地址和端口的每个请求,即未用于任何其他虚拟主机的地址/端口组合。
<VirtualHost _default_:*> DocumentRoot "/www/default" </VirtualHost>
使用带有通配符端口的默认虚拟主机可以有效地阻止任何请求进入主服务器。
默认虚拟主机从不提供发送到用于基于名称的虚拟主机的地址/端口的请求。如果请求包含未知或无Host:标头,则始终从基于主名称的虚拟主机(配置文件中首先出现的该地址/端口的虚拟主机)提供服务。
您可以使用AliasMatch
或RewriteRule
将任何请求重写到单个信息页面(或脚本)。
default vhosts 用于不同的端口
与上面的设置相同,但服务器侦听多个端口,我们希望将第二个_default_ vhost
用于端口80
。
<VirtualHost _default_:80> DocumentRoot "/www/default80" # ... </VirtualHost> <VirtualHost _default_:*> DocumentRoot "/www/default" # ... </VirtualHost>
端口80
的默认虚拟主机(必须出现在具有通配符端口的任何默认虚拟主机之前)会捕获发送到未指定IP地址的所有请求。主服务器从不用于提供请求。
default vhosts用于一个端口
我们希望端口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的虚拟主机)和旧地址(作为基于名称的虚拟主机)访问虚拟主机。
我们有一个带有两个基于名称的虚拟主机的服务器。为了匹配正确的虚拟主机,客户端必须发送正确的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
指令,始终从sub1-vhost
提供对URL http://www.sub1.domain.tld/sub1/
的请求。
如果客户端发送了正确的Host:头,则仅从sub1-vhost
提供对URL http://www.sub1.domain.tld/
的请求。如果没有发送Host:头,则客户端从主要主机获取信息页面。
请注意,有一个奇怪之处:如果客户端没有发送Host:头,则还会从sub1-vhost
提供对http://www.sub2.domain.tld/sub1/
的请求。