Apache HTTP Server 版本2.2
本文檔試圖解釋一些在設(shè)置虛擬主機(jī)時(shí)經(jīng)常問(wèn)及的問(wèn)題。這些示例向你展示了如何在一個(gè)服務(wù)器上通過(guò)基于域名的或是基于IP的虛擬主機(jī)來(lái)部署多個(gè)web站點(diǎn)。另一份關(guān)于如何在一個(gè)代理服務(wù)器后構(gòu)建基于多個(gè)服務(wù)器的站點(diǎn)的說(shuō)明文檔也很快就會(huì)出來(lái)。
您的服務(wù)器有只一個(gè)IP地址,而在DNS中有很多域名(CNAMES)映射到這個(gè)機(jī)器。您而您想要在這個(gè)機(jī)器上運(yùn)行www.example.com
和www.example.org
兩個(gè)站點(diǎn)。
在您的Apache服務(wù)器配置中創(chuàng)建一個(gè)虛擬主機(jī)并不會(huì)自動(dòng)在您的DNS中對(duì)主機(jī)名做相應(yīng)更新。您必須自己在DNS中添加域名來(lái)指向您的IP地址。否則別人是無(wú)法看到您的web站點(diǎn)的。您可以在您的hosts
文件中添加這一條目來(lái)進(jìn)行測(cè)試,但這種方法僅適用于那些有這些hosts
文件的機(jī)器來(lái)使用。
# 確保Apache在監(jiān)聽(tīng)80端口
Listen 80
# 為虛擬主機(jī)在所有IP地址上監(jiān)聽(tīng)
NameVirtualHost *:80
<VirtualHost *:80>
DocumentRoot /www/example1
ServerName www.example.com
# 你可以在這里添加其他指令
</VirtualHost>
<VirtualHost *:80>
DocumentRoot /www/example2
ServerName www.example.org
# 你可以在這里添加其他指令
</VirtualHost>
因?yàn)樾翘?hào)匹配所有IP地址,所以主服務(wù)器不接收任何請(qǐng)求。因?yàn)?code>www.example.com首先出現(xiàn)在配置文件中,所以它擁有最高優(yōu)先級(jí),可以認(rèn)為是默認(rèn)或主服務(wù)器。這意味著如果一個(gè)請(qǐng)求不能與某個(gè)ServerName
指令相匹配,它將會(huì)由第一個(gè)<VirtualHost>
段所伺服。
如果您愿意,您可以用確定的IP地址來(lái)取代"*
"。在這種情況下,VirtualHost
的參數(shù)必須與NameVirtualHost
的參數(shù)相符:
NameVirtualHost 172.20.30.40
<VirtualHost 172.20.30.40>
# 其他 ...
然而,當(dāng)您的IP地址無(wú)法確定的時(shí)候,使用"*
"是很方便的,比如說(shuō),您的ISP給您配置的是動(dòng)態(tài)IP地址,而您又使用了某種動(dòng)態(tài)域名解析系統(tǒng)時(shí)。因?yàn)?*
"匹配任何IP地址,所以在這種情況下,不論IP地址如何變化,您都不需要另外進(jìn)行配置。
上述配置就是您在絕大多數(shù)情況下使用基于域名的虛擬主機(jī)時(shí)將要用到的。事實(shí)上,僅在一種情況下這樣的配置不會(huì)讓您滿(mǎn)意:您想為不同的IP地址或是端口提供不同的內(nèi)容。
在這里討論的任何技術(shù)都可以推廣到使用任意數(shù)量的IP地址。
服務(wù)器有兩個(gè)IP地址。一個(gè)(172.20.30.40
)用于主服務(wù)器server.domain.com
,另外一個(gè)(172.20.30.50
)用于構(gòu)建兩個(gè)或多個(gè)虛擬主機(jī)。
Listen 80
# "主"服務(wù)器運(yùn)行于:172.20.30.40
ServerName server.domain.com
DocumentRoot /www/mainserver
# 這是另外一個(gè)IP地址
NameVirtualHost 172.20.30.50
<VirtualHost 172.20.30.50>
DocumentRoot /www/example1
ServerName www.example.com
# 你可以在這里添加其他指令 ...
</VirtualHost>
<VirtualHost 172.20.30.50>
DocumentRoot /www/example2
ServerName www.example.org
# 你可以在這里添加其他指令 ...
</VirtualHost>
任何不是針對(duì)172.20.30.50
的請(qǐng)求都將由主服務(wù)器來(lái)伺服。而提交給172.20.30.50
卻沒(méi)有主機(jī)名或沒(méi)有"Host:
"頭的請(qǐng)求,都將由www.example.com
伺服。
服務(wù)器有兩個(gè)IP地址(192.168.1.1
和172.20.30.40
)。這個(gè)機(jī)器位于內(nèi)部(局域網(wǎng))網(wǎng)絡(luò)和外部(廣域網(wǎng))之間。在外部,域名server.example.com
指向外部地址(172.20.30.40
),而在內(nèi)部則指向內(nèi)部地址(192.168.1.1
)。
服務(wù)器可以為來(lái)自?xún)?nèi)部和外部的請(qǐng)求提供同樣的內(nèi)容,您只需要一個(gè)<VirtualHost>
配置段就可以了。
NameVirtualHost 192.168.1.1
NameVirtualHost 172.20.30.40
<VirtualHost 192.168.1.1 172.20.30.40>
DocumentRoot /www/server1
ServerName server.example.com
ServerAlias server
</VirtualHost>
現(xiàn)在,從不同的網(wǎng)絡(luò)提交的請(qǐng)求都會(huì)由同一個(gè)<VirtualHost>
段來(lái)伺服。
在內(nèi)網(wǎng)中,您可以使用server
這個(gè)名字來(lái)代替server.example.com
這個(gè)全名。
跟上面一樣,在上述的例子里,您可以用"*
"來(lái)代替具體的IP地址,這樣就可以對(duì)所有的地址都返回相同的內(nèi)容了。
如果您想讓同一個(gè)IP的不同端口伺服多個(gè)域名。您可以借助在NameVirtualHost
指令中定義端口的方法來(lái)達(dá)到這個(gè)目的。如果您想使用不帶"name:port
"的<VirtualHost name:port>
或是直接用Listen
指令,您的配置將無(wú)法生效。
Listen 80
Listen 8080
NameVirtualHost 172.20.30.40:80
NameVirtualHost 172.20.30.40: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>
一個(gè)有兩個(gè)IP地址(172.20.30.40
和172.20.30.50
)分別對(duì)應(yīng)域名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>
如果存在主服務(wù)器,那么對(duì)沒(méi)有出現(xiàn)在任一個(gè)<VirtualHost>
段中的請(qǐng)求(比如,對(duì)localhost
的請(qǐng)求)都會(huì)由主服務(wù)器來(lái)伺服。
如果您的服務(wù)器有兩個(gè)IP地址(172.20.30.40
和172.20.30.50
)分別對(duì)應(yīng)域名www.example.com
和www.example.org
。對(duì)每個(gè)域名,您都希望在80端口和8080端口發(fā)布您的網(wǎng)站。您可以這樣配置:
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>
您想在一些地址上配置基于域名的虛擬主機(jī)而在另外一些地址上配置基于IP的虛擬主機(jī)。
Listen 80
NameVirtualHost 172.20.30.40
<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.example3.net
</VirtualHost>
# IP-based
<VirtualHost 172.20.30.50>
DocumentRoot /www/example4
ServerName www.example4.edu
</VirtualHost>
<VirtualHost 172.20.30.60>
DocumentRoot /www/example5
ServerName www.example5.gov
</VirtualHost>
<Virtual_host>
和mod_proxy
模塊一起使用下面的例子允許一個(gè)前端機(jī)器代理一個(gè)運(yùn)行在其他機(jī)器上的虛擬主機(jī)。在如下示例中,在192.168.111.2
機(jī)器上配置了一個(gè)同名的虛擬主機(jī)。這樣,萬(wàn)一在同一臺(tái)機(jī)器上代理了多個(gè)主機(jī)名,ProxyPreserveHost On
指令能確保指定的主機(jī)名順利通過(guò)代理。
<VirtualHost *:*>
ProxyPreserveHost On
ProxyPass / http://192.168.111.2
ProxyPassReverse / http://192.168.111.2/
ServerName hostname.example.com
</VirtualHost>
_default_
"虛擬主機(jī)_default_
"虛擬主機(jī)這樣配置可以捕獲所有指向沒(méi)指定的IP地址和端口的請(qǐng)求。比如:一個(gè)沒(méi)被任何虛擬主機(jī)使用的地址/端口對(duì)。
<VirtualHost _default_:*>
DocumentRoot /www/default
</VirtualHost>
這樣一個(gè)使用通配符端口的默認(rèn)虛擬主機(jī)可以有效的防止請(qǐng)求被主服務(wù)器接收。
如果一個(gè)地址/端口對(duì)已經(jīng)被一個(gè)基于域名的虛擬主機(jī)使用,那么"_default_
"虛擬主機(jī)決不會(huì)處理發(fā)向這個(gè)地址/端口對(duì)的請(qǐng)求。如果一個(gè)"Host:
"請(qǐng)求頭中包含未知信息,或者干脆就沒(méi)有,那么它會(huì)被第一個(gè)基于域名的虛擬主機(jī)(也就是在配置文件中最先出現(xiàn)的使用了那個(gè)地址/端口對(duì)的虛擬主機(jī))處理。
您可以用AliasMatch
或RewriteRule
來(lái)重寫(xiě)任何請(qǐng)求,使它指向一個(gè)簡(jiǎn)單信息頁(yè)面(或腳本)。
_default_
"虛擬主機(jī)與第一種一樣,但我們想讓服務(wù)器偵聽(tīng)很多端口而第二個(gè)"_default_
"虛擬主機(jī)單獨(dú)偵聽(tīng)80端口。
<VirtualHost _default_:80>
DocumentRoot /www/default80
# ...
</VirtualHost>
<VirtualHost _default_:*>
DocumentRoot /www/default
# ...
</VirtualHost>
偵聽(tīng)80端口的"_default_
"虛擬主機(jī)(必須出現(xiàn)在所有使用通配符端口的虛擬主機(jī)之前)會(huì)捕獲所有發(fā)向一個(gè)未指定的IP地址的請(qǐng)求。主服務(wù)器將不會(huì)用于伺服任何請(qǐng)求。
_default_
"虛擬主機(jī)如果我們只想在80端口上建立唯一的一個(gè)"_default_
"虛擬主機(jī),我們應(yīng)該這樣配置:
<VirtualHost _default_:80>
DocumentRoot /www/default
...
</VirtualHost>
發(fā)向一個(gè)未指定地址的80端口的請(qǐng)求將會(huì)由這個(gè)虛擬主機(jī)伺服;而發(fā)向未設(shè)定地址的其他端口的請(qǐng)求則由主服務(wù)器伺服。
如果一個(gè)具有www.example.org
域名的虛擬主機(jī)(就是基于域名配置示例中的第二個(gè))得到了自己的IP地址。為了避免一些域名服務(wù)器或代理服務(wù)器在移植期間仍對(duì)這個(gè)域名做老的解析,我們可以采用一種過(guò)渡方法:同時(shí)提供新舊兩個(gè)IP地址的解析。
達(dá)到這個(gè)目的很簡(jiǎn)單。因?yàn)槲覀冎灰?jiǎn)單的把新地址(172.20.30.50
)加入VirtualHost
指令就行了。
Listen 80
ServerName www.example.com
DocumentRoot /www/example1
NameVirtualHost 172.20.30.40
<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>
現(xiàn)在這個(gè)虛擬主機(jī)就可以用新地址(表現(xiàn)為一個(gè)基于IP的虛擬主機(jī))和舊地址(表現(xiàn)為一個(gè)基于域名的虛擬主機(jī))同時(shí)進(jìn)行訪問(wèn)了。
ServerPath
指令如果我們?cè)谕粋(gè)服務(wù)器上運(yùn)行了兩個(gè)基于域名的虛擬主機(jī)。為了匹配正確的虛擬主機(jī),客戶(hù)端必須發(fā)送正確的"Host:
"頭。而舊的使用HTTP/1.0的客戶(hù)端無(wú)法發(fā)送這樣的頭,這樣Apache就無(wú)法辨別客戶(hù)端想要連接哪個(gè)虛擬主機(jī)(會(huì)用主虛擬主機(jī)來(lái)伺服這個(gè)請(qǐng)求)。為了盡量提供向下兼容性,我們可以提供一個(gè)主虛擬主機(jī)來(lái)返回一個(gè)頁(yè)面,在頁(yè)面中加入指向基于域名的虛擬主機(jī)的URL前綴的鏈接。
NameVirtualHost 172.20.30.40
<VirtualHost 172.20.30.40>
# 主虛擬主機(jī)
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
指令的作用,發(fā)送到http://www.sub1.domain.tld/sub1/
的請(qǐng)求總會(huì)被sub1-vhost所伺服。
如果客戶(hù)端發(fā)送了正確的"Host:
"頭,發(fā)送到http://www.sub1.domain.tld/
的請(qǐng)求只會(huì)被sub1-vhost所伺服。如果沒(méi)有發(fā)送"Host:
"頭,客戶(hù)端將會(huì)得到從主虛擬主機(jī)發(fā)送的信息頁(yè)面。
請(qǐng)注意,這里還有一點(diǎn)小問(wèn)題:如果客戶(hù)端沒(méi)有發(fā)送"Host:
"頭,發(fā)送到http://www.sub2.domain.tld/sub1/
的請(qǐng)求還是會(huì)被sub1-vhost所伺服。
RewriteRule
指令用以確保正確發(fā)送了"Host:
"頭的客戶(hù)端可以任意使用這兩種URL變量,比如說(shuō):使用或不使用URL前綴。