10.5 虚拟网站主机功能

如果每台运行Linux系统的服务器上只能运行一个网站,那么人气低、流量小的草根站长就要被迫承担着高昂的服务器租赁费用了,这显然也会造成硬件资源的浪费。在虚拟专用服务器(Virtual Private Server,VPS)与云计算技术诞生以前,IDC服务供应商为了能够更充分地利用服务器资源,同时也为了降低购买门槛,于是纷纷启用了虚拟主机功能。

利用虚拟主机功能,可以把一台处于运行状态的物理服务器分割成多个“虚拟的服务器”。但是,该技术无法实现目前云主机技术的硬件资源隔离,让这些虚拟的服务器共同使用物理服务器的硬件资源,供应商只能限制硬盘的使用空间大小。出于各种考虑的因素(主要是价格低廉),目前依然有很多企业或个人站长在使用虚拟主机的形式来部署网站。

Apache的虚拟主机功能是服务器基于用户请求的不同IP地址、主机域名或端口号,实现提供多个网站同时为外部提供访问服务的技术,如图10-12所示,用户请求的资源不同,最终获取到的网页内容也各不相同。如果大家之前没有做过网站,可能不太理解其中的原理,等一会儿搭建出实验环境并看到实验效果之后,您一定就会明白了。

再次提醒大家,在做每个实验之前请先将虚拟机还原到最初始状态,以免多个实验之间相互产生冲突。

Apache虚拟主机功能拓扑

图10-12 用户请求网站资源[原图附件]

10.5.1 基于IP地址

如果一台服务器有多个IP地址,而且每个IP地址与服务器上部署的每个网站一一对应,这样当用户请求访问不同的IP地址时,会访问到不同网站的页面资源。而且,每个网站都有一个独立的IP地址,对搜索引擎优化也大有裨益。因此以这种方式提供虚拟网站主机功能不仅最常见,也受到了网站站长的欢迎(尤其是草根站长)。

刘遄老师在第4章和第9章分别讲解了用于配置网络的两种方法,大家在实验中和工作中可随意选择。就当前的实验来讲,需要配置的IP地址如图10-13所示。在配置完毕并重启网卡服务之后,记得检查网络的连通性,确保三个IP地址均可正常访问,如图10-14所示(这很重要,一定要测试好,然后再进行下一步!)。 nmtui对网卡添加多IP地址

图10-13 使用nmtui命令配置网络参数

第1步:分别在/home/wwwroot中创建用于保存不同网站数据的3个目录,并向其中分别写入网站的首页文件。每个首页文件中应有明确区分不同网站内容的信息,方便我们稍后能更直观地检查效果。 确认网卡配置正确

图10-14 分别检查3个IP地址的连通性

  1. [root@linuxprobe ~]# mkdir -p /home/wwwroot/10
  2. [root@linuxprobe ~]# mkdir -p /home/wwwroot/20
  3. [root@linuxprobe ~]# mkdir -p /home/wwwroot/30
  4. [root@linuxprobe ~]# echo "IP:192.168.10.10" > /home/wwwroot/10/index.html
  5. [root@linuxprobe ~]# echo "IP:192.168.10.20" > /home/wwwroot/20/index.html
  6. [root@linuxprobe ~]# echo "IP:192.168.10.30" > /home/wwwroot/30/index.html

第2步:在httpd服务的配置文件中大约113行处开始,分别追加写入三个基于IP地址的虚拟主机网站参数,然后保存并退出。记得需要重启httpd服务,这些配置才生效。

  1. [root@linuxprobe ~]# vim /etc/httpd/conf/httpd.conf
  2. ………………省略部分输出信息………………
  3. 113 <VirtualHost 192.168.10.10>
  4. 114 DocumentRoot /home/wwwroot/10
  5. 115 ServerName www.linuxprobe.com
  6. 116 <Directory /home/wwwroot/10 >
  7. 117 AllowOverride None
  8. 118 Require all granted
  9. 119 </Directory>
  10. 120 </VirtualHost>
  11. 121 <VirtualHost 192.168.10.20>
  12. 122 DocumentRoot /home/wwwroot/20
  13. 123 ServerName bbs.linuxprobe.com
  14. 124 <Directory /home/wwwroot/20 >
  15. 125 AllowOverride None
  16. 126 Require all granted
  17. 127 </Directory>
  18. 128 </VirtualHost>
  19. 129 <VirtualHost 192.168.10.30>
  20. 130 DocumentRoot /home/wwwroot/30
  21. 131 ServerName tech.linuxprobe.com
  22. 132 <Directory /home/wwwroot/30 >
  23. 133 AllowOverride None
  24. 134 Require all granted
  25. 135 </Directory>
  26. 136 </VirtualHost>
  27. ………………省略部分输出信息………………
  28. [root@linuxprobe ~]# systemctl restart httpd

第3步:此时访问网站,则会看到httpd服务程序的默认首页面。大家现在应该立刻就反应过来—这是SELinux在捣鬼。由于当前的/home/wwwroot目录及里面的网站数据目录的SELinux安全上下文与网站服务不吻合,因此httpd服务程序无法获取到这些网站数据目录。我们需要手动把新的网站数据目录的SELinux安全上下文设置正确(见前文的实验),并使用restorecon命令让新设置的SELinux安全上下文立即生效,这样就可以立即看到网站的访问效果了,如图10-15所示。

  1. [root@linuxprobe ~]# semanage fcontext -a -t httpd_sys_content_t /home/wwwroot
  2. [root@linuxprobe ~]# semanage fcontext -a -t httpd_sys_content_t /home/wwwroot/10
  3. [root@linuxprobe ~]# semanage fcontext -a -t httpd_sys_content_t /home/wwwroot/10/*
  4. [root@linuxprobe ~]# semanage fcontext -a -t httpd_sys_content_t /home/wwwroot/20
  5. [root@linuxprobe ~]# semanage fcontext -a -t httpd_sys_content_t /home/wwwroot/20/*
  6. [root@linuxprobe ~]# semanage fcontext -a -t httpd_sys_content_t /home/wwwroot/30
  7. [root@linuxprobe ~]# semanage fcontext -a -t httpd_sys_content_t /home/wwwroot/30/*
  8. [root@linuxprobe ~]# restorecon -Rv /home/wwwroot
  9. restorecon reset /home/wwwroot context unconfined_u:object_r:home_root_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0
  10. restorecon reset /home/wwwroot/10 context unconfined_u:object_r:home_root_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0
  11. restorecon reset /home/wwwroot/10/index.html context unconfined_u:object_r:home_root_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0
  12. restorecon reset /home/wwwroot/20 context unconfined_u:object_r:home_root_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0
  13. restorecon reset /home/wwwroot/20/index.html context unconfined_u:object_r:home_root_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0
  14. restorecon reset /home/wwwroot/30 context unconfined_u:object_r:home_root_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0
  15. restorecon reset /home/wwwroot/30/index.html context unconfined_u:object_r:home_root_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0
  16. [root@linuxprobe ~]# firefox

验证基于IP地址的虚拟主机功能的结果

图10-15 基于不同的IP地址访问虚拟主机网站

10.5.2 基于主机域名

当服务器无法为每个网站都分配一个独立IP地址的时候,可以尝试让Apache自动识别用户请求的域名,从而根据不同的域名请求来传输不同的内容。在这种情况下的配置更加简单,只需要保证位于生产环境中的服务器上有一个可用的IP地址(这里以192.168.10.10为例)就可以了。由于当前还没有介绍如何配置DNS解析服务,因此需要手工定义IP地址与域名之间的对应关系。/etc/hosts是Linux系统中用于强制把某个主机域名解析到指定IP地址的配置文件。简单来说,只要这个文件配置正确,即使网卡参数中没有DNS信息也依然能够将域名解析为某个IP地址。

第1步:手工定义IP地址与域名之间对应关系的配置文件,保存并退出后会立即生效。可以通过分别ping这些域名来验证域名是否已经成功解析为IP地址。

  1. [root@linuxprobe ~]# vim /etc/hosts
  2. 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
  3. ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
  4. 192.168.10.10 www.linuxprobe.com bbs.linuxprobe.com tech.linuxprobe.com
  5. [root@linuxprobe ~]# ping -c 4 www.linuxprobe.com
  6. PING www.linuxprobe.com (192.168.10.10) 56(84) bytes of data.
  7. 64 bytes from www.linuxprobe.com (192.168.10.10): icmp_seq=1 ttl=64 time=0.070 ms
  8. 64 bytes from www.linuxprobe.com (192.168.10.10): icmp_seq=2 ttl=64 time=0.077 ms
  9. 64 bytes from www.linuxprobe.com (192.168.10.10): icmp_seq=3 ttl=64 time=0.061 ms
  10. 64 bytes from www.linuxprobe.com (192.168.10.10): icmp_seq=4 ttl=64 time=0.069 ms
  11. --- www.linuxprobe.com ping statistics ---
  12. 4 packets transmitted, 4 received, 0% packet loss, time 2999ms
  13. rtt min/avg/max/mdev = 0.061/0.069/0.077/0.008 ms
  14. [root@linuxprobe ~]#

第2步:分别在/home/wwwroot中创建用于保存不同网站数据的三个目录,并向其中分别写入网站的首页文件。每个首页文件中应有明确区分不同网站内容的信息,方便我们稍后能更直观地检查效果。

  1. [root@linuxprobe ~]# mkdir -p /home/wwwroot/www
  2. [root@linuxprobe ~]# mkdir -p /home/wwwroot/bbs
  3. [root@linuxprobe ~]# mkdir -p /home/wwwroot/tech
  4. [root@linuxprobe ~]# echo "WWW.linuxprobe.com" > /home/wwwroot/www/index.html
  5. [root@linuxprobe ~]# echo "BBS.linuxprobe.com" > /home/wwwroot/bbs/index.html
  6. [root@linuxprobe ~]# echo "TECH.linuxprobe.com" > /home/wwwroot/tech/index.html

第3步:在httpd服务的配置文件中大约113行处开始,分别追加写入三个基于主机名的虚拟主机网站参数,然后保存并退出。记得需要重启httpd服务,这些配置才生效。

  1. [root@linuxprobe ~]# vim /etc/httpd/conf/httpd.conf
  2. ………………省略部分输出信息………………
  3. 113 <VirtualHost 192.168.10.10>
  4. 114 DocumentRoot "/home/wwwroot/www"
  5. 115 ServerName "www.linuxprobe.com"
  6. 116 <Directory "/home/wwwroot/www">
  7. 117 AllowOverride None
  8. 118 Require all granted
  9. 119 </directory>
  10. 120 </VirtualHost>
  11. 121 <VirtualHost 192.168.10.10>
  12. 122 DocumentRoot "/home/wwwroot/bbs"
  13. 123 ServerName "bbs.linuxprobe.com"
  14. 124 <Directory "/home/wwwroot/bbs">
  15. 125 AllowOverride None
  16. 126 Require all granted
  17. 127 </Directory>
  18. 128 </VirtualHost>
  19. 129 <VirtualHost 192.168.10.10>
  20. 130 DocumentRoot "/home/wwwroot/tech"
  21. 131 ServerName "tech.linuxprobe.com"
  22. 132 <Directory "/home/wwwroot/tech">
  23. 133 AllowOverride None
  24. 134 Require all granted
  25. 135 </directory>
  26. 136 </VirtualHost>
  27. ………………省略部分输出信息………………

第4步:因为当前的网站数据目录还是在/home/wwwroot目录中,因此还是必须要正确设置网站数据目录文件的SELinux安全上下文,使其与网站服务功能相吻合。最后记得用restorecon命令让新配置的SELinux安全上下文立即生效,这样就可以立即访问到虚拟主机网站了,效果如图10-16所示。

  1. [root@linuxprobe ~]# semanage fcontext -a -t httpd_sys_content_t /home/wwwroot
  2. [root@linuxprobe ~]# semanage fcontext -a -t httpd_sys_content_t /home/wwwroot/www
  3. [root@linuxprobe ~]# semanage fcontext -a -t httpd_sys_content_t /home/wwwroot/www/*
  4. [root@linuxprobe ~]# semanage fcontext -a -t httpd_sys_content_t /home/wwwroot/bbs
  5. [root@linuxprobe ~]# semanage fcontext -a -t httpd_sys_content_t /home/wwwroot/bbs/*
  6. [root@linuxprobe ~]# semanage fcontext -a -t httpd_sys_content_t /home/wwwroot/tech
  7. [root@linuxprobe ~]# semanage fcontext -a -t httpd_sys_content_t /home/wwwroot/tech/*
  8. [root@linuxprobe ~]# restorecon -Rv /home/wwwroot
  9. reset /home/wwwroot context unconfined_u:object_r:home_root_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0
  10. restorecon reset /home/wwwroot/www context unconfined_u:object_r:home_root_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0
  11. restorecon reset /home/wwwroot/www/index.html context unconfined_u:object_r:home_root_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0
  12. restorecon reset /home/wwwroot/bbs context unconfined_u:object_r:home_root_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0
  13. restorecon reset /home/wwwroot/bbs/index.html context unconfined_u:object_r:home_root_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0
  14. restorecon reset /home/wwwroot/tech context unconfined_u:object_r:home_root_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0
  15. restorecon reset /home/wwwroot/tech/index.html context unconfined_u:object_r:home_root_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0
  16. [root@linuxprobe ~]# firefox

验证虚拟主机功能结果

图10-16 基于主机域名访问虚拟主机网站

10.5.3 基于端口号

基于端口号的虚拟主机功能可以让用户通过指定的端口号来访问服务器上的网站资源。在使用Apache配置虚拟网站主机功能时,基于端口号的配置方式是最复杂的。因此我们不仅要考虑httpd服务程序的配置因素,还需要考虑到SELinux服务对新开设端口的监控。一般来说,使用80、443、8080等端口号来提供网站访问服务是比较合理的,如果使用其他端口号则会受到SELinux服务的限制。

在接下来的实验中,我们不但要考虑到目录上应用的SELinux安全上下文的限制,还需要考虑SELinux域对httpd服务程序的管控。

第1步:分别在/home/wwwroot中创建用于保存不同网站数据的两个目录,并向其中分别写入网站的首页文件。每个首页文件中应有明确区分不同网站内容的信息,方便我们稍后能更直观地检查效果。

  1. [root@linuxprobe ~]# mkdir -p /home/wwwroot/6111
  2. [root@linuxprobe ~]# mkdir -p /home/wwwroot/6222
  3. [root@linuxprobe ~]# echo "port:6111" > /home/wwwroot/6111/index.html
  4. [root@linuxprobe ~]# echo "port:6222" > /home/wwwroot/6222/index.html

第2步:在httpd服务配置文件的第43行和第44行分别添加用于监听6111和6222端口的参数。

  1. [root@linuxprobe ~]# vim /etc/httpd/conf/httpd.conf
  2. ………………省略部分输出信息………………
  3. 33 #
  4. 34 # Listen: Allows you to bind Apache to specific IP addresses and/or
  5. 35 # ports, instead of the default. See also the <VirtualHost>
  6. 36 # directive.
  7. 37 #
  8. 38 # Change this to Listen on specific IP addresses as shown below to
  9. 39 # prevent Apache from glomming onto all bound IP addresses.
  10. 40 #
  11. 41 #Listen 12.34.56.78:80
  12. 42 Listen 80
  13. 43 Listen 6111
  14. 44 Listen 6222
  15. ………………省略部分输出信息………………

第3步:在httpd服务的配置文件中大约113行处开始,分别追加写入两个基于端口号的虚拟主机网站参数,然后保存并退出。记得需要重启httpd服务,这些配置才生效。

  1. [root@linuxprobe ~]# vim /etc/httpd/conf/httpd.conf
  2. ………………省略部分输出信息………………
  3. 113 <VirtualHost 192.168.10.10:6111>
  4. 114 DocumentRoot "/home/wwwroot/6111"
  5. 115 ServerName www.linuxprobe.com
  6. 116 <Directory "/home/wwwroot/6111">
  7. 117 AllowOverride None
  8. 118 Require all granted
  9. 119 </Directory>
  10. 120 </VirtualHost>
  11. 121 <VirtualHost 192.168.10.10:6222>
  12. 122 DocumentRoot "/home/wwwroot/6222"
  13. 123 ServerName bbs.linuxprobe.com
  14. 124 <Directory "/home/wwwroot/6222">
  15. 125 AllowOverride None
  16. 126 Require all granted
  17. 127 </Directory>
  18. 128 </VirtualHost>
  19. ………………省略部分输出信息………………

第4步:因为我们把网站数据目录存放在/home/wwwroot目录中,因此还是必须要正确设置网站数据目录文件的SELinux安全上下文,使其与网站服务功能相吻合。最后记得用restorecon命令让新配置的SELinux安全上下文立即生效。

  1. [root@linuxprobe ~]# semanage fcontext -a -t httpd_sys_content_t /home/wwwroot
  2. [root@linuxprobe ~]# semanage fcontext -a -t httpd_sys_content_t /home/wwwroot/6111
  3. [root@linuxprobe ~]# semanage fcontext -a -t httpd_sys_content_t /home/wwwroot/6111/*
  4. [root@linuxprobe ~]# semanage fcontext -a -t httpd_sys_content_t /home/wwwroot/6222
  5. [root@linuxprobe ~]# semanage fcontext -a -t httpd_sys_content_t /home/wwwroot/6222/*
  6. [root@linuxprobe ~]# restorecon -Rv /home/wwwroot/
  7. restorecon reset /home/wwwroot context unconfined_u:object_r:home_root_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0
  8. restorecon reset /home/wwwroot/6111 context unconfined_u:object_r:home_root_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0
  9. restorecon reset /home/wwwroot/6111/index.html context unconfined_u:object_r:home_root_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0
  10. restorecon reset /home/wwwroot/6222 context unconfined_u:object_r:home_root_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0
  11. restorecon reset /home/wwwroot/6222/index.html context unconfined_u:object_r:home_root_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0
  12. [root@linuxprobe ~]# systemctl restart httpd
  13. Job for httpd.service failed. See 'systemctl status httpd.service' and 'journalctl -xn' for details.

见鬼了!在妥当配置httpd服务程序和SELinux安全上下文并重启httpd服务后,竟然出现报错信息。这是因为SELinux服务检测到6111和6222端口原本不属于Apache服务应该需要的资源,但现在却以httpd服务程序的名义监听使用了,所以SELinux会拒绝使用Apache服务使用这两个端口。我们可以使用semanage命令查询并过滤出所有与HTTP协议相关且SELinux服务允许的端口列表。

  1. [root@linuxprobe ~]# semanage port -l | grep http
  2. http_cache_port_t tcp 8080, 8118, 8123, 10001-10010
  3. http_cache_port_t udp 3130
  4. http_port_t tcp 80, 81, 443, 488, 8008, 8009, 8443, 9000
  5. pegasus_http_port_t tcp 5988
  6. pegasus_https_port_t tcp 5989

第5步:SELinux允许的与HTTP协议相关的端口号中默认没有包含6111和6222,因此需要将这两个端口号手动添加进去。该操作会立即生效,而且在系统重启过后依然有效。设置好后再重启httpd服务程序,然后就可以看到网页内容了,结果如图10-17所示。

  1. [root@linuxprobe ~]# semanage port -a -t http_port_t -p tcp 6111
  2. [root@linuxprobe ~]# semanage port -a -t http_port_t -p tcp 6222
  3. [root@linuxprobe ~]# semanage port -l| grep http
  4. http_cache_port_t tcp 8080, 8118, 8123, 10001-10010
  5. http_cache_port_t udp 3130
  6. http_port_t tcp 6222, 6111, 80, 81, 443, 488, 8008, 8009, 8443, 9000
  7. pegasus_http_port_t tcp 5988
  8. pegasus_https_port_t tcp 5989
  9. [root@linuxprobe ~]# systemctl restart httpd
  10. [root@linuxprobe ~]# firefox

基于端口虚拟主机实验成功

图10-17 基于端口号访问虚拟主机网站