24 Feb 2022
apache有两种配置virtualhost的方式,一种是基于IP(ip based),另外一种是基于名称(name based)。
关于apache的virtualhost详细文档,可以参见httpd 官方文档
基于IP的方式中,多个daemon还是单个daemon的问题,这里不讨论,可以参见上面提供的官方文档查看详细信息
另一个需要注意的点是,使用基于名称的虚拟主机配置时,在httpd的配置文件中,最先加载的virtualhost配置为默认的虚拟主机
通常,大部分情况下,我们常用的是使用基于名称的虚拟主机配置方式。
有一天,在某办公室的神秘对话:
开发:运维同学,我想要用ip访问apache,辛苦您帮我配置一下 运维:好的
这个场景中,也是使用的更常见的基于名称的虚拟主机的配置方式
运维思索了一下,找出了以下方案:
这两个方案中,第一个方案有明显的缺点,因为生产环境中通常都会给默认虚拟主机设定访问限制,来禁止使用ip或者其他未经授权的域名解析来访问服务器,只有那些明确监听的域名才会被响应。而第二个方案,运维同学心里有点打鼓,不确定同时拥有默认虚拟主机和将ServerName配置为IP的情况下,apache会使用哪个来发起响应。所以运维同学决定来验证一下。
配置三个虚拟主机,第一个是默认虚拟主机,访问会返回“from default”;第二个是配置ServerName为ip(127.0.0.1 & 192.168.1.124)的虚拟主机,访问会返回“from ip virtualhost”;第三个是配置了本地测试域名“test.local.net”的虚拟主机,访问会返回“from test.local.net”。三个虚拟主机是按照介绍的顺序依次从上到下排列。
虽然我们给ServerName配置了IP,但是使用ServerName本身实际上还是使用的基于名字的虚拟主机配置类型。
mkdir -p {conf/vhosts.d,www/{default,ip,test.local.net}} sudo echo "127.0.0.1 test.local.net" >> /etc/hosts # 准备 httpd 配置文件 cat << EOF > conf/vhosts.d/00-default.conf <VirtualHost *:80> DocumentRoot "/www/default" <Directory "/www/default"> Require all granted </Directory> </VirtualHost> EOF cat << EOF > conf/vhosts.d/01-ip.conf <VirtualHost *:80> DocumentRoot "/www/ip" ServerName 127.0.0.1:80 ServerAlias 192.168.1.124:80 <Directory "/www/ip"> Require all granted </Directory> </VirtualHost> EOF cat << EOF > conf/vhosts.d/02-test.local.net <VirtualHost *:80> DocumentRoot "/www/test.local.net" ServerName test.local.net:80 <Directory "/www/test.local.net"> Require all granted </Directory> </VirtualHost> EOF # 准备不同虚拟主机的网站文件 cat << EOF > www/default/index.html from default EOF cat << EOF > www/ip/index.html from ip virtualhost EOF cat << EOF > www/test.local.net/index.html from test.local.net EOF # httpd:2.4.51使用的网站用户的uid是33,需要正确的授权 sudo chown -R 33.33 www # 准备基于docker的启动脚本 cat << EOF > start.sh docker run -it -d --rm --name httpd \ -p 80:80 \ -v $(pwd)/www:/www \ -v $(pwd)/conf/httpd.conf:/usr/local/apache2/conf/httpd.conf \ -v $(pwd)/conf/vhosts.d:/usr/local/apache2/conf/vhosts.d \ httpd:2.4.51 EOF
sh start.sh
首先,我们简单的使用curl访问一下,看看结果
curl 127.0.0.1 from ip virtualhost curl 192.168.1.124 from ip virtualhost curl test.local.net from test.local.net
结果符合预期,每个访问都得到了设想的结果。
在《httpd基于名字的虚拟主机文档》中发现了这样的说明。
首先,请求进来后,apache先通过ip:port来筛选。然后,再使用ServerName和ServerAlias来进行进一步匹配。若匹配到了,则响应请求,若未匹配到,就会进一步使用默认虚拟主机来响应。
在这个过程中,ServerName和ServerAlias部分的匹配,使用的是请求中的”Host”首部。
那么,来手动修改“Host”首部来验证一下
curl -H "Host: 127.0.0.1" test.local.net from ip virtualhost curl -H "Host: test.local.net" 192.168.1.124 from test.local.net curl -H "Host: nonexist.com" 192.168.1.124 from default
果然,返回的内容竟然和请求的url无关,而是和“Host”首部强关联。比如访问test.local.net返回的竟然是“from ip virtualhost”,这和”Host: 127.0.0.1”首部相对应。