Apache2 虚拟主机注意点

下面这个是使用 VirtualHost 过程中的注意事项,分 Ip Based 以及 Domain Based。

# ifconfig
eth0      Link encap:Ethernet  HWaddr 00:13:3e:13:11:06 
          inet addr:111.111.111.111  Bcast:111.111.111.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:57203592 errors:0 dropped:0 overruns:0 frame:0
          TX packets:21655208 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:85022831734 (85.0 GB)  TX bytes:1540881922 (1.5 GB)
          Interrupt:10

eth1      Link encap:Ethernet  HWaddr 00:13:3e:13:11:17 
          inet addr:10.18.10.252  Bcast:10.18.10.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:6982 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1249 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:1122466 (1.1 MB)  TX bytes:535239 (535.2 KB)
          Interrupt:11

eth1:1    Link encap:Ethernet  HWaddr 00:13:3e:13:11:17 
          inet addr:10.18.10.251  Bcast:10.18.10.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          Interrupt:11

lo        Link encap:Local Loopback 
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:12 errors:0 dropped:0 overruns:0 frame:0
          TX packets:12 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:984 (984.0 B)  TX bytes:984 (984.0 B)

1.Ip Based

没有必要设置 NameVirtualHost 指令。VirtualHost 紧邻 addr:port,addr 建议使用 IP 的方式而非 FQDN 的方式。如果要使用 * 则必须跟 NameVirtualHost 结合使用,或者下面演示的 _default_ 方式。

$ cat /etc/apache2/sites-available/ip-based

<VirtualHost 10.18.10.252:80>
    DocumentRoot /var/www/a
</VirtualHost>
<VirtualHost 10.18.10.251:80>
    DocumentRoot /var/www/b
</VirtualHost>
<VirtualHost 10.18.10.251:8000>
    DocumentRoot /var/www/a
</VirtualHost>
<VirtualHost _default_:*>
    DocumentRoot /var/www/c
</VirtualHost>

基于 IP 的用的比较少,内部实验性质的可以试试。


2.Domain Based

NameVirtualHost 指令是专门用在基于域名的访问方式中的,因此在基于域名的配置中,它是必须的,在基于 IP 的配置中,非必要。同样的 ServerName 也是必须的。
NameVirtualHost 跟 VirtualHost 一样,官方都建议使用 IP 形式的 addr 而非 hostname。接下来的所有操作均参照文档上的建议。

注意:VirtualHost 的 addr:port 必须严格的匹配 NameVirtualHost 的 addr:port。实际操作下来,NameVirtualHost 有包含 VirtualHost 的关系,也就是说 NameVirtualHost 的范围可以更大些。

Now when a request arrives, the server will first check if it is using an IP address that matches the NameVirtualHost. If it is, then it will look at each <VirtualHost> section with a matching IP address and try to find one where the ServerName or ServerAlias matches the requested hostname. If it finds one, then it uses the configuration for that server. If no matching virtual host is found, then the first listed virtual host that matches the IP address will be used.

上面这段话描述了一个请求过来之后解析顺序。首先跟 NameVirtualHost 后面的 addr:ip 匹配,匹配成功,将会接着匹配 VirtualHost 后面的 addr:ip 并且匹配与请求的主机名相同的 ServerName 或 ServerAlias。如果没有 ServerName/ServerAlias 匹配,将使用符合这个 VirtualHost 的第一个虚拟主机,如果连 VirtualHost 都不匹配,则会找 _default_ 配置的虚拟主机,再找不到 404。

下面三个域名:

a.jaseywang.me
b.jaseywang.me
c.jaseywang.me
aaa.a.jaseywang.me

都指向同一个 A 记录,假设是 111.111.111.111。建立测试页面:

# mkdir /var/www/{a,b,c,d};cd /var/www
# echo a > a/index.html
# echo b > b/index.html
# echo c > c/index.html
# echo d > d/index.html

需要 a2ensite 的文件是 domain-based:

NameVirtualHost *:80
NameVirtualHost *:8000

<VirtualHost *:80>
DocumentRoot /var/www/a
ServerName a.jaseywang.me
</VirtualHost>

<VirtualHost *:80>
DocumentRoot /var/www/b
ServerName b.jaseywang.me
ServerAlias aaa.a.jaseywang.me
</VirtualHost>

<VirtualHost *:80>
DocumentRoot /var/www/c
ServerName c.jaseywang.me
</VirtualHost>

<VirtualHost *:8000>
DocumentRoot /var/www/d
ServerName c.jaseywang.me
</VirtualHost>

上面这个是比较标准的一种配置方式,下面这个就违反了上面的规则,所以访问 b.jaseywang.me 以及 c.jaseywang.me 会看到 a 而不是期望中的 b 跟 c。

NameVirtualHost *:80
NameVirtualHost *:8000

<VirtualHost 111.111.111.111:80>
DocumentRoot /var/www/a
ServerName a.jaseywang.me
</VirtualHost>

<VirtualHost 111.111.111.111:80>
DocumentRoot /var/www/b
ServerName b.jaseywang.me
ServerAlias aaa.a.jaseywang.me
</VirtualHost>

<VirtualHost 111.111.111.111:80>
DocumentRoot /var/www/c
ServerName c.jaseywang.me
</VirtualHost>

<VirtualHost 111.111.111.111:8000>
DocumentRoot /var/www/d
ServerName c.jaseywang.me
</VirtualHost>

上面这个在重启 apache2 的时候就会看到 warning 了,如果忽略了 warning,仍然可以访问网页,但是已经不是你所期望的:

# /etc/init.d/apache2 restart
 * Restarting web server apache2
[Sat Feb 04 17:37:53 2012] [warn] VirtualHost 111.111.111.111:80 overlaps with VirtualHost 111.111.111.111:80, the first has precedence, perhaps you need a NameVirtualHost directive
[Sat Feb 04 17:37:53 2012] [warn] VirtualHost 111.111.111.111:80 overlaps with VirtualHost 111.111.111.111:80, the first has precedence, perhaps you need a NameVirtualHost directive
[Sat Feb 04 17:37:53 2012] [warn] NameVirtualHost *:8000 has no VirtualHosts
[Sat Feb 04 17:37:53 2012] [warn] NameVirtualHost *:80 has no VirtualHosts
 … waiting [Sat Feb 04 17:37:54 2012] [warn] VirtualHost 111.111.111.111:80 overlaps with VirtualHost 111.111.111.111:80, the first has precedence, perhaps you need a NameVirtualHost directive
[Sat Feb 04 17:37:54 2012] [warn] VirtualHost 111.111.111.111:80 overlaps with VirtualHost 111.111.111.111:80, the first has precedence, perhaps you need a NameVirtualHost directive
[Sat Feb 04 17:37:54 2012] [warn] NameVirtualHost *:8000 has no VirtualHosts
[Sat Feb 04 17:37:54 2012] [warn] NameVirtualHost *:80 has no VirtualHosts
                                                                                                                                 [ OK ]

ref:
http://httpd.apache.org/docs/2.2/