Apache HTTP Server 虚拟主机配置(三)
什么是虚拟主机
"虚拟主机"是指在一个机器上运行多个网站(比如:www.company1.com和 www.company2.com)。如果每个网站拥有不同的IP地址,则虚拟主机可以是"基于IP"的;如果只有一个IP地址,也可以是"基于主机名"的,其实现对最终用户是透明的。物理服务器只有一个,而且web服务器也只有一个,却可以服务多个不同的站点。
如果要调试你的虚拟主机配置,你会发现Apache的 -S 命令行开关很有用。比如:
# httpd -S虚拟主机类型支持
[*] 基于主机名的虚拟主机(一个IP地址,多个网站)
同IP,同端口,不同域名,虽然被解析到同一个IP上,但是通过http头的 host 能够区分
[*] 基于IP地址的虚拟主机(每个站点拥有一个的独立IP地址)
不同IP, 同端口,每个虚拟主机使用不同的IP地址(但是IP地址有点贵)
[*] 基于端口的虚拟主机
同IP,不同端口,但是困扰的是浏览器默认的端口都是80
基于IP的虚拟主机使用连接的IP地址来决定相应的虚拟主机。这样,你就需要为每个虚拟主机分配一个独立的IP地址。而基于域名的虚拟主机是根据客户端提交的HTTP头中标识主机名的部分决定的。使用这种技术,很多虚拟主机可以共享同一个IP地址。
基于域名的虚拟主机相对比较简单,因为你只需要配置你的DNS服务器将每个主机名映射到正确的IP地址,然后配置Apache HTTP服务器,令其辨识不同的主机名就可以了。基于域名的服务器也可以缓解IP地址不足的问题。所以,如果没有特殊原因使你必须使用基于IP的虚拟主机,您最好还是使用基于域名的虚拟主机。
基于IP的虚拟主机使用连接的IP地址来决定相应的虚拟主机。这样,你就需要为每个虚拟主机分配一个独立的IP地址。而基于域名的虚拟主机是根据客户端提交的HTTP头中标识主机名的部分决定的。使用这种技术,很多虚拟主机可以共享同一个IP地址。
我们知道,TCP/IP网络通信都是建立在 socket之上的。就能唯一标识网络上的哪个主机哪个进程。当我们通过浏览器访问:http://www.baidu.com 的时候,首先DNS会把www.baidu.com这个域名解析为IP地址,然后才能在网络中路由。既然域名都会被解析为IP地址,那么怎么实现基于域名的虚拟主机呢?
仅仅是TCP/IP是无法做到的,但是HTTP协议却能够实现这一点。在http协议首部,定义了一个 host 参数,通过它就可以区分究竟访问的哪个虚拟主机。httpd 可以根据 host 区分到底访问的是哪一个虚拟主机。
《HTTP权威指南》
缺失主机信息是原始HTTP规范的疏忽,它错误的假设每个web服务器上只托管了一个网站。在这个期间涌现了以下4种技术来解决这个问题。
(1)通过URL路径进行虚拟主机托管
在url中添加专门的路径部分,以便服务器判断是哪个网站。
(2)通过端口号进行主机托管
为每个站点分配一个端口号。
(3)通过IP地址进行主机托管
为不同的虚拟站点分配专门的ip地址,把这些地址绑定到一台单独的机器上。
(4)通过Host首部进行主机托管
通过Htpp/1.0增强版和HTTP/1.1正式版定义Host请求首部来携带网站名称。
[*] 通过URL路径进行虚拟主机托管
通过分配不同的url路径,把共享服务器上的虚拟站点隔离开。
如:
http://www.xx123.com/zyt/index.html
http://www.xx356.com/icrt/index.html
当请求到达服务时,其中并没有主机信息,但是服务器可以通过路径来区分它们。请求zyt的网址是:GET /zyt/index.html,请求icrt的网址是: GET /icrt/index.html 这不是一个好办法/zyt 和/icrt是多余的,更坏的是http://www.xx123.com和http://www.xx356.com不能用了。
这种方案在实际中很少会用到。
[*] 通过端口号进行主机托管
可在在web服务器上为不同网站指定不同的端口号,不再使用80端口,而是采用其它端口号。这个解决方案也有问题:终端用户不乐意在url中指定非标准的端口号。如http://www.xx123.com:89
[*] 通过IP地址进行主机托管
通过ip地址进行主机托管,是一个更常用、更好的办法。为每个虚拟网站分配一个或者多个唯一的ip地址。所有虚拟网站的ip地址都绑定到同一个共享服务器上。服务器可以查询http连接的目的ip地址,并以此来判断客户端的目标网站。
如:把ip:209.173.34.3分配给www.xxx123.com,把ip:209.172.34.2分配给www.xx356.com,把这两个ip地址都绑定到同一物理服务器上。
但是这样做也会带来一些麻烦:首先在计算机系统上能够绑定的虚拟ip地址通常是有限制的,其次ip地址是稀缺资源,最后托管都通过复制服务器来增加容量时,ip地址短缺的问题就更加严重了。尽管有这样的缺陷,但是它仍然得到广泛的应用。
[*] 通过Host首部进行主机托管
为了避免过度的地址消耗和虚拟ip地址的限制,我们希望在虚拟站点间共享同一个ip地址,且仍然能够区分站点。为了解决这个问题,浏览器来服务器的实现都扩展了HTTP,把原始主机名给了服务器。不过,浏览器不能只发送完整的URL,因为这会使许多只能接收路径的服务器无法工作。替代的方法是,把主机名和端口号放在所请求的Host扩展首部中传送。
绝大多数现代浏览器和服务器都支持Host首部,但仍然有一些客户端以及网络机器人不支持它。
配置虚拟主机
对于Apache而言,主机有两类(中心主机和虚拟主机):不能同时使用,如果要定义虚拟主机,那么必须为现存的主机也创建一个
[*] 中心主机(Mainhost) 未配置虚拟主机时
[*] 虚拟主机(Vhost) 如果配置了中心主机,同时也想配置虚拟主机,那么把中心主机也配置虚拟主机
[*] 取消中心主机(Mainhost)
一、如果你想在现有的web服务器上增加虚拟主机,你必须也为现存的主机建造一个定义块。这个虚拟主机中ServerName和DocumentRoot所包含的内容应该与全局的ServerName和DocumentRoot保持一致。还要把这个虚拟主机放在配置文件的最前面,来让它扮演默认主机的角色。
二、如果不想使用中心主机,那么可以直接在httpd.conf配置文件中注释掉中心主机的 DocumentRoot即可。
[*] 虚拟主机的配置文件
可以直接在主配置文件httpd.conf中直接配置,但是这样不利于维护,建议在/etc/httpd/conf.d/建立 *.conf 配置文件。前提是在httpd.conf中配置 Include conf.d/*.conf
我们通过指令来定义虚拟主机,ServerNmae和DocumentRoot是一个虚拟主机最基本的两个配置,其他可以在中心主机配置的指令,基本都可以应用于虚拟主机。
ServerName
DocumentRoot "/path/to/"
基于域名的虚拟主机(推荐使用该方式)
注意,在您的Apache服务器配置中创建一个基于域名虚拟主机并不会自动在您的DNS中对主机名做相应的更新。您必须自己在DNS中添加域名来指向您的IP地址。否则别人是无法访问您的web站点的。也可以在hosts文件中添加这一条目进行测试,但是这种方法仅适用于那些有这些hosts条目的机器来使用。
为了使用基于域名的虚拟主机,你必须指定服务器IP地址(和可能的端口)来使主机接受请求,这个可以用 NameVirtualHost 指令来进行配置。如果服务器上所有的IP地址都会用到,你可以用"*"作为NameVirtualHost的参数。如果你打算使用多端口(如运行SSL)你必须在参数中指定一个端口号,比如"*:80"。请注意,在NameVirtualHost指令中指定IP地址并不会使服务器自动侦听那个IP地址。请参阅设置Apache使用的地址和端口一章获取更多详情。另外,这里设定的IP地址必须对应服务器上的一个网络接口。
这样,当一个请求到达的时候,服务器会首先检查它是否使用了一个能和NameVirtualHost相匹配的IP地址。如果能够匹配,它就会查找每个与这个IP地址相对应的段,并尝试找出一个与请求的主机名相同的ServerName或ServerAlias配置项。如果找到了,它就会使用这个服务器。否则,将使用符合这个IP地址的第一个列出的虚拟主机。
综上所述,第一个列出的虚拟主机充当了默认虚拟主机的角色。当一个IP地址与NameVirtualHost指令中的配置相符的时候,主服务器中的DocumentRoot将永远不会被用到。所以,如果你想创建一段特殊的配置用于处理不对应任何一个虚拟主机的请求的话,你只要简单的把这段配置放到段中,并把它放到配置文件的最前面就可以了。
需要注意的是:apache2.2 需要用 NameVirtualHost 指令配置, apache2.4 不需要
下一步就是为每个虚拟主机建立段。的参数与NameVirtualHost的参数必须是一样的(比如说,一个IP地址或"*"代表的所有地址)。在每个段中,至少要有一个ServerName指令来指定伺服哪个主机和一个DocumentRoot指令来说明这个主机的内容位于文件系统的什么地方。
[*] ServerName
[*] DocumentRoot
以下试验中,请注意 iptables, SELinux 的设置;
# 修改配置文件
# vi /etc/httpd/conf.d/virtual.conf
NameVirtualHost *:80 # apache 2.2 必须
ServerName www.a.com
DocumentRoot "/www/a.com"
ServerName www.b.org
DocumentRoot "/www/b.org"
# 创建web目录
# mkdir -pv /www/a.com /www/b.org
mkdir: created directory `/www'
mkdir: created directory `/www/a.com'
mkdir: created directory `/www/b.org'
# 编辑index.html
# echo 'www.a.com' > /www/a.com/index.html
# echo 'www.b.org' > /www/b.org/index.html
# 检查虚拟主机配置
# httpd -S
httpd: apr_sockaddr_info_get() failed for skype
httpd: Could not reliably determine the server's fully qualified domain name, using 127.0.0.1 for ServerName
VirtualHost configuration:
wildcard NameVirtualHosts and _default_ servers:
*:80 is a NameVirtualHost
default server www.a.com (/etc/httpd/conf.d/virtual.conf:3)
port 80 namevhost www.a.com (/etc/httpd/conf.d/virtual.conf:3)
port 80 namevhost www.b.org (/etc/httpd/conf.d/virtual.conf:8)
# 重新载入配置文件
# service httpd reload
# 我们只能通过域名进行访问,如果直接使用IP,那么则会返回默认的虚拟主机。
# 1 可以修改客户机的host文件, win: C:\Windows\System32\drivers\etc
# 2 也可以搭建内部的DNS服务器进行解析
# 编辑hosts文件,有些机器的hosts可能被隐藏了
192.168.11.101www.a.com
192.168.11.101www.b.org
C:\Users\yy>ping www.a.com
正在 Ping www.a.com 具有 32 字节的数据:
来自 192.168.11.101 的回复: 字节=32 时间 /www/a.com/index.html
# echo '192.168.11.102' > /www/b.org/index.html
# 如何测试呢?我们通过添加网卡别名来达成
# ifconfig eth1
eth1 Link encap:EthernetHWaddr 00:0C:29:FB:65:36
inet addr:192.168.11.101Bcast:192.168.11.255Mask:255.255.255.0
inet6 addr: fe80::20c:29ff:fefb:6536/64 Scope:Link
UP BROADCAST RUNNING MULTICASTMTU:1500Metric:1
RX packets:168196 errors:0 dropped:0 overruns:0 frame:0
TX packets:44037 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:197148682 (188.0 MiB)TX bytes:3998845 (3.8 MiB)
Interrupt:19 Base address:0x2080
# ifconfig eth1:0 192.168.11.102/24 up # 添加网卡别名
基于端口的虚拟主机
基于端口的虚拟主机在生产环境用的不多,因为客户端浏览器默认都是80端口,客户端并不知道我们配置端口是什么。除了通过链接地址进行跳转的情况以及公司内部使用。
必须配置httpd监听端口: Listen PORT(极为重要)
# vi /etc/httpd/conf.d/virtual.conf
NameVirtualHost *:80
serverName www.a.com
DocumentRoot "/www/a.com"
serverName www.b.org
DocumentRoot "/www/b.org"
# 修改主配置文件,修改监听端口(非常重要)
# 这样httpd才能向linux内核(BIND)注册端口,然后TCP/IP协议栈才知道把包传给哪个应用程序。
# vi /etc/httpd/conf/httpd.conf
Listen 80
Listen 8080
#httpd -t
# service httpd restart # 由于修改了端口,需要restart
# echo '192.168.11.101: 80' > /www/a.com/index.html
# echo '192.168.11.101: 8080' > /www/b.org/index.html 如果开启了防火墙,请检查防火墙设置,添加其端口的入站规则。
总结
定义一个站点,至少需要提供如下信息:
[*] DocumentRoot
[*] ServerName
[*] IP
[*] PORT
如果测试无法正常访问, 请检查iptables防火墙规则,以及SELinux设置。
更多详细信息, 请参考Apache官方网站。
页:
[1]