Apache HTTP Server 版本2.2
虛擬主機(jī)部分的代碼在Apache 1.3中進(jìn)行了完全的重寫(xiě)。本文檔試圖詳細(xì)解釋Apache在接受到請(qǐng)求后如何確定使用哪一個(gè)虛擬主機(jī)進(jìn)行伺服。在新的NameVirtualHost
指令的幫助下,虛擬主機(jī)的配置比1.3版以前更加簡(jiǎn)單和安全。
如果您只是想讓它能夠工作而不愿意進(jìn)行深入理解,這里有一些示例。
在<VirtualHost>
配置段外有一個(gè)主服務(wù)器(main_server)段中包含著所有定義。其中有<VirtualHost>
配置段中定義的叫做虛擬主機(jī)(vhost)的虛擬服務(wù)器。
Listen
, ServerName
, ServerPath
, ServerAlias
指令可以出現(xiàn)在一個(gè)服務(wù)器定義段的任何地方。而且每個(gè)指令都會(huì)覆蓋前面出現(xiàn)的同樣定義(在那個(gè)服務(wù)器配置中)。
主服務(wù)器段中Listen
指令的默認(rèn)值是80。主服務(wù)器段沒(méi)有默認(rèn)的ServerPath
和ServerAlias
指令值。ServerName
的默認(rèn)值是由服務(wù)器的IP地址推斷而來(lái)。
主服務(wù)器的Listen
指令有兩個(gè)功能:其一是決定Apache將要綁定的網(wǎng)絡(luò)端口;其二是在重定向中指定絕對(duì)URI將使用的端口號(hào)。
不象在主服務(wù)器里,虛擬服務(wù)器的端口不會(huì)影響到Apache的監(jiān)聽(tīng)端口。
每個(gè)VirtualHost
指令中的地址都可以附帶一個(gè)可選的端口。如果沒(méi)有進(jìn)行特別的指定,這個(gè)端口默認(rèn)為主服務(wù)器中最近的一個(gè)Listen
指令指定的值。特殊的端口"*
"表示匹配所有端口。所有這一系列地址(包括由DNS查詢(xún)出的所有A
記錄)統(tǒng)稱(chēng)虛擬主機(jī)的地址集(address set)。
如果沒(méi)有對(duì)一個(gè)特定的IP地址使用NameVirtualHost
指令,那么第一個(gè)使用這個(gè)地址的虛擬主機(jī)將被視為基于IP的虛擬主機(jī)。IP地址也可以用通配符"*
"表示。
如果使用了基于域名的虛擬主機(jī),那么必須用NameVirtualHost
指令為這個(gè)基于域名的虛擬主機(jī)指定IP地址集。換句話說(shuō),您必須在配置文件中通過(guò)NameVirtualHost
指令指定包括主機(jī)名映射(CNAME)的IP地址。
可以使用很多NameVirtualHost
指令來(lái)分別對(duì)應(yīng)一套NameVirtualHost
指令,但對(duì)于每個(gè)特定的"IP:port"對(duì)來(lái)說(shuō),只能使用一次NameVirtualHost
指令。
NameVirtualHost
和VirtualHost
指令出現(xiàn)的順序并不重要。只有對(duì)應(yīng)同一個(gè)IP地址的VirtualHost
指令的次序才是重要的。所以下面兩例所起的作用是完全相同的:
|
|
(為了使您的配置文件更具可讀性,我們推薦您使用左邊的格式)
在解析完VirtualHost
指令后,虛擬主機(jī)服務(wù)器將被賦予在它的VirtualHost
指令中第一個(gè)名字對(duì)應(yīng)的端口作為默認(rèn)的Listen
端口。
如果所有域名都指向同一個(gè)地址集的話,VirtualHost
指令中的所有域名列表都將會(huì)得到和ServerAlias
指令一樣的處理(但不會(huì)被其他ServerAlias
語(yǔ)句覆蓋)。請(qǐng)注意,這個(gè)虛擬主機(jī)自帶的Listen
指令將不能影響到那個(gè)地址集的端口號(hào)。
在初始化的過(guò)程中,將會(huì)為每一個(gè)IP地址產(chǎn)生一個(gè)列表,并插入到一個(gè)散列表中。如果這個(gè)IP地址是用在一個(gè)NameVirtualHost
指令中的,這個(gè)列表將會(huì)包含所有指定為這個(gè)IP地址的基于域名的虛擬主機(jī)。如果沒(méi)有虛擬主機(jī)針對(duì)這個(gè)IP地址,那么NameVirtualHost
指令將被忽略,并會(huì)在日志中記錄一個(gè)錯(cuò)誤信息。對(duì)于基于IP的虛擬主機(jī)而言,這個(gè)散列表中的列表為空。
因?yàn)槭褂昧烁咝У纳⒘兴惴,使得在?qǐng)求到達(dá)的時(shí)候在其中查找IP地址的開(kāi)銷(xiāo)變得很小,或者根本不需考慮。而且這個(gè)表格還為只有最后一個(gè)八進(jìn)制位不同的IP地址做了優(yōu)化。
虛擬主機(jī)的每個(gè)變量都有初始值。特別是以下這些:
ServerAdmin
, ResourceConfig
, AccessConfig
, Timeout
, KeepAliveTimeout
, KeepAlive
, MaxKeepAliveRequests
, ReceiveBufferSize
, SendBufferSize
指令,那么將從主服務(wù)器繼承它們的值。(也就是說(shuō),使用在主服務(wù)器中最后出現(xiàn)的設(shè)定值)。本質(zhì)上,主服務(wù)器在建立每個(gè)虛擬主機(jī)的時(shí)候,充當(dāng)了一個(gè)默認(rèn)值或根基的角色。但這些存在于主服務(wù)器中的定義的位置是無(wú)關(guān)緊要的——主服務(wù)器的配置在與虛擬主機(jī)整合之前就已經(jīng)解析過(guò)了。所以即使一個(gè)主服務(wù)器的配置出現(xiàn)在虛擬主機(jī)定義的后面,它也同樣會(huì)影響到虛擬主機(jī)的配置。
如果沒(méi)有定義主服務(wù)器中的ServerName
,那么將由運(yùn)行這個(gè)httpd
服務(wù)的機(jī)器的主機(jī)名來(lái)代替。我們將由DNS查找此ServerName
返回的IP地址稱(chēng)為主服務(wù)器地址集(main_server address set)。
在沒(méi)有定義ServerName
的情況下,一個(gè)基于域名的虛擬主機(jī)默認(rèn)采用定義虛擬主機(jī)時(shí)在VirtualHost
指令中最先出現(xiàn)的地址。
所有使用了"_default_
"通配符的虛擬主機(jī)將被賦予和主服務(wù)器相同的ServerName
。
服務(wù)器用下述方法來(lái)確定對(duì)一個(gè)特定的請(qǐng)求使用哪個(gè)虛擬主機(jī):
當(dāng)客戶(hù)端第一次連接的時(shí)候,會(huì)從內(nèi)部的IP散列表中查找客戶(hù)端想要連接的IP地址。
如果查找失敗(沒(méi)有找到相應(yīng)的IP地址),而所請(qǐng)求的端口又存在一個(gè)"_default_
"虛擬主機(jī),那么這個(gè)請(qǐng)求將會(huì)由這個(gè)虛擬主機(jī)來(lái)伺服。如果沒(méi)有找到這樣的"_default_
"虛擬主機(jī),那么這個(gè)請(qǐng)求將會(huì)由主服務(wù)器來(lái)伺服。
如果在散列表中沒(méi)有找到IP地址,但存在一個(gè)"NameVirtualHost *
"指令與所請(qǐng)求的端口號(hào)相匹配,那么將用這個(gè)虛擬主機(jī)來(lái)處理這個(gè)請(qǐng)求。
如果查找成功(找到了對(duì)應(yīng)于這個(gè)IP地址的列表),下一步就是看我們要處理的是一個(gè)基于IP的虛擬主機(jī)還是一個(gè)基于域名的虛擬主機(jī)。
如果返回的列表中域名列表為空,那么我們處理的就是一個(gè)基于IP的虛擬主機(jī),這個(gè)虛擬主機(jī)將會(huì)直接進(jìn)行處理而不會(huì)有其他步驟。
如果返回的域名列表包含一個(gè)或多個(gè)虛擬主機(jī)的結(jié)構(gòu),那么我們處理的就是一個(gè)基于域名的虛擬主機(jī)。這個(gè)列表包含的虛擬主機(jī)的順序與配置文件中相應(yīng)VirtualHost
指令出現(xiàn)的順序是相同的。
這個(gè)列表中第一個(gè)虛擬主機(jī)(也就是在配置文件中第一個(gè)指定了這個(gè)IP地址的虛擬主機(jī))對(duì)處理請(qǐng)求有著最高的優(yōu)先級(jí)。所有對(duì)未知服務(wù)器名或沒(méi)有"Host:
"頭的請(qǐng)求都將由它進(jìn)行處理。
如果客戶(hù)端在請(qǐng)求中提供了一個(gè)"Host:
"頭,那么將在列表中查找第一個(gè)ServerName
或ServerAlias
與其符合的虛擬主機(jī),并將其用于伺服這個(gè)請(qǐng)求。盡管"Host:
"頭中可以包含端口號(hào),但Apache還是會(huì)用收到請(qǐng)求的那個(gè)真實(shí)端口來(lái)進(jìn)行匹配。
如果客戶(hù)端提交了一個(gè)不包含"Host:
"頭的HTTP/1.0的請(qǐng)求,我們將無(wú)法確認(rèn)客戶(hù)端想要連接那個(gè)服務(wù)器。而如果存在一個(gè)ServerPath
與客戶(hù)端提交的請(qǐng)求中的URI相對(duì)應(yīng),那么列表中第一個(gè)符合條件的虛擬主機(jī)將用于伺服這個(gè)請(qǐng)求。
如果還是找不到對(duì)應(yīng)的虛擬主機(jī),那么這個(gè)請(qǐng)求將會(huì)由客戶(hù)端連接的IP對(duì)應(yīng)的列表中的第一個(gè)與請(qǐng)求的端口相同的虛擬主機(jī)來(lái)伺服(如前所述)。
上述IP查找對(duì)一個(gè)特定的TCP/IP進(jìn)程只執(zhí)行一次。但在持久連接(KeepAlive)中,每個(gè)請(qǐng)求都會(huì)進(jìn)行一次這樣的查找過(guò)程。換句話說(shuō),一個(gè)客戶(hù)端在一個(gè)持久連接中可以向位于不同的基于域名的虛擬主機(jī)的頁(yè)面提出請(qǐng)求。
如果請(qǐng)求提交的URI是一個(gè)絕對(duì)URI,而其中的主機(jī)名和端口號(hào)又和主服務(wù)器或某個(gè)虛擬主機(jī)相符合,并且也與作為此請(qǐng)求提交對(duì)象的地址和端口相符,那么這個(gè)請(qǐng)求的類(lèi)型/主機(jī)名/端口前綴將被抹除,僅留下相對(duì)URI為對(duì)應(yīng)的主服務(wù)器或虛擬主機(jī)所伺服。如果不滿(mǎn)足上述符合條件,這個(gè)URI將保留原樣,而此請(qǐng)求將被作為一個(gè)代理請(qǐng)求處理。
NameVirtualHost
指令定義的地址集的訪問(wèn)。ServerAlias
和ServerPath
檢查。_default_
"虛擬主機(jī)和NameVirtualHost
指令出現(xiàn)的順序并不重要。而對(duì)于某個(gè)指定的地址集來(lái)說(shuō),基于域名的虛擬主機(jī)的順序是不能混淆的:在配置文件中較先出現(xiàn)的虛擬主機(jī)在相應(yīng)的地址集中有較高的優(yōu)先權(quán)。Host:
"頭中出現(xiàn)的端口號(hào)將不用于匹配。Apache會(huì)一直使用客戶(hù)端所連接的真實(shí)端口作為匹配。ServerPath
指令湊巧是后面出現(xiàn)的另外一個(gè)ServerPath
指令的前綴,前者將用于匹配,而后者將被忽略。(這里討論的是沒(méi)有"Host:
"頭來(lái)將這兩個(gè)情況分開(kāi)的情況下)_default_
"虛擬主機(jī)才會(huì)捕獲這個(gè)請(qǐng)求。并且僅當(dāng)"_default_
"虛擬主機(jī)的端口號(hào)(默認(rèn)值由您的Listen
指定)與客戶(hù)端發(fā)送請(qǐng)求的目的端口號(hào)相符時(shí),這個(gè)請(qǐng)求才會(huì)被捕獲。也可以使用通配符(例如:"_default_:*
")來(lái)捕獲任何端口號(hào)的請(qǐng)求。這也同樣適用于"NameVirtualHost *
"的虛擬主機(jī)。_default_
"虛擬主機(jī))匹配的時(shí)候,才會(huì)用主服務(wù)器來(lái)伺服請(qǐng)求。換句話說(shuō),主服務(wù)器僅捕獲沒(méi)有指定IP地址和端口的請(qǐng)求(除非存在一個(gè)匹配端口的"_default_
"虛擬主機(jī))。NameVirtualHost
指令,那么一個(gè)未知的或沒(méi)有"Host:
"頭的請(qǐng)求就不會(huì)與"_default_
"虛擬主機(jī)或是主服務(wù)器相匹配。VirtualHost
指令中使用DNS名稱(chēng),否則您的服務(wù)器就會(huì)依賴(lài)DNS來(lái)進(jìn)行啟動(dòng)。而且,如果您無(wú)法控制列表中所有的域,您將會(huì)面臨安全威脅。您可以在這里獲得關(guān)于這個(gè)問(wèn)題和以下兩個(gè)問(wèn)題的更多詳情。ServerName
。否則就會(huì)需要為每個(gè)虛擬主機(jī)進(jìn)行DNS查詢(xún)。作為DNS問(wèn)題頁(yè)面小技巧的附加,這里有些額外的技巧:
VirtualHost
定義之前(為了增加可讀性),否則會(huì)使得類(lèi)似在虛擬主機(jī)旁邊的定義影響到所有的虛擬主機(jī)這樣的問(wèn)題不容易發(fā)現(xiàn)。NameVirtualHost
和VirtualHost
定義放到一起,以獲得更好的可讀性。ServerPaths
是后一個(gè)ServerPaths
的前綴。如果您無(wú)法避免這樣的情況,您最好確保在您的配置文件中"長(zhǎng)在前,短在后"(也就是說(shuō):"ServerPath/abc/def"應(yīng)當(dāng)出現(xiàn)在"ServerPath/abc"之前)。