Apache HTTP Server 2.4 版
本文探討 Apache HTTP Server 決定提供哪一個虛擬主機的請求時,確切採取的步驟。
大多數使用者應先參閱 基於名稱與基於 IP 的虛擬主機 來決定要使用的類型,接著再深入了解 基於名稱 或 基於 IP 的虛擬主機,然後參閱 一些範例。
如果您想了解所有詳情,可以再回來此頁面。
「主伺服器」由顯示於 <VirtualHost>
區段之外的所有定義組成。
虛擬伺服器稱為「虛擬主機」,由 <VirtualHost>
區段定義。
每個 VirtualHost
指令都包含一個或多個位址,以及選用的連接埠。
可在虛擬主機定義中使用網域名稱取代 IP 位址,但它們會在開機時解析,若任何名稱解析失敗,則會略過那些虛擬主機定義。因此,不建議這樣做。
位址可指定為 *
,若沒有其他虛擬主機具有請求接收到的明確位址,則將比對請求。
在 VirtualHost
指令中顯示的位址可以選擇性指定連接埠。若未指定連接埠,將視為通配符連接埠,也可以使用 *
明確標示。通配符連接埠會比對任何連接埠。
(在 VirtualHost
指令中指定埠號不會影響 Apache 監聽的埠號,它們只能控制將選取哪個 VirtualHost
來處理請求。使用 Listen
指令控制伺服器監聽的位址和埠號。)
所有位址的集合(包括 DNS 查詢的多個結果)稱為 vhost 的「位址集合」。
只要 Apache 在多個虛擬主機中列出 IP 位址和埠號組合最明確的比對,Apache 就會自動根據客戶端提供的 HTTP Host
標頭進行區分。
當 ServerName
指令出現在伺服器定義中的任何位置,每個出現都會覆寫前一個出現(同一伺服器中)。如果沒有指定 ServerName
,伺服器會嘗試從伺服器的 IP 位址推論。
針對特定 IP:port 組合,設定檔中的第一個基於名稱的 vhost 具有重要性,因為它會用於接收該位址和埠號的所有請求,而其他 vhost 對該 IP:port 組合沒有配對的 ServerName 或 ServerAlias。如果伺服器不支援 伺服器名稱指示,它也會用於所有 SSL 連線。
VirtualHost
指令中的完整名稱清單會像(非萬用字元)ServerAlias
一樣處理(但不會被任何 ServerAlias
陳述覆寫)。
為每個 vhost 設定各種預設值。特別是
ServerAdmin
、Timeout
、KeepAliveTimeout
、KeepAlive
、MaxKeepAliveRequests
、ReceiveBufferSize
或 SendBufferSize
指令,則會從主伺服器繼承相應的值。(亦即從主伺服器中該值的最終設定中繼承。)基本上,主伺服器被視為每個 vhost 的「預設值」或「基礎」來建置。不過,主伺服器定義在設定檔中的位置基本上無關緊要 -- 當進行此次最後合併時,主伺服器的完整設定都已進行分析。因此,即使主伺服器定義出現在 vhost 定義之後,它也可能會影響 vhost 定義。
如果主伺服器在此時沒有 ServerName
,則會使用執行著 httpd
的機器主機名稱。我們將主伺服器的 ServerName
上透過 DNS 查詢傳回的 IP 位址稱為主伺服器位址組。
對於任何未定義的 ServerName
欄位,以名稱為基礎的虛擬主機預設為在定義虛擬主機的 VirtualHost
陳述式中最早提供的位址。
包含神奇通配字 _default_
的任何虛擬主機都獲得與主伺服器相同的 ServerName
。
伺服器決定請求應使用哪個虛擬主機的方法如下
當連線在某個位址和埠口首次接收時,伺服器會尋找具有相同 IP 位址和埠口的 VirtualHost
的所有定義。
如果沒有與位址和埠口完全匹配的項目,則會考慮使用通配字 (*
) 匹配。
如果找不到任何匹配的項目,則請求會由主伺服器提供服務。
如果存在針對 IP 位址的 VirtualHost
定義,下一步便是決定我們必須處理基於 IP 的虛擬主機還是基於名稱的虛擬主機。
如果只有一個 VirtualHost
指示列出了被確定為最佳匹配項的 IP 位址和埠口組合,則不會執行進一步的動作,且請求將由匹配的虛擬主機提供服務。
如果有多個 VirtualHost
指示列出了被確定為最佳匹配項的 IP 位址和埠口組合,則在剩餘步驟中的「清單」指的是與配置檔案中順序相同的已匹配虛擬主機的清單。
如果連線使用 SSL,則伺服器支援 伺服器名稱指示 而且 SSL 客戶端交握包含要求的主機名稱的 TLS 擴充元,則該主機名稱會在下方像非 SSL 連線上使用的 Host:
標頭一樣使用。否則,第一個位址匹配的名稱為基礎的虛擬主機會被用於 SSL 連線。此點很重要,因為虛擬主機會決定伺服器將為連線使用哪張憑證。
如果請求包含 Host:
標頭欄位,則在清單中搜尋第一個具有匹配 ServerName
或 ServerAlias
的虛擬主機,且請求將由該虛擬主機提供服務。Host:
標頭欄位可以包含埠口號碼,但 Apache 會始終忽略它,並根據客戶端發送請求的實際埠口進行匹配。
在設定檔中使用指定 IP 位址的第一個 vhost 優先權最高,並擷取任何針對未知伺服器名稱的請求,或沒有 Host:
標頭欄位的請求(例如 HTTP/1.0 請求)。
上述IP 查詢對於特定 TCP/IP 階段僅執行一次,而名稱查詢則會在 KeepAlive/持續連線期間針對每個請求執行。換句話說,客戶端可能在單一持續連線期間從不同的基於名稱的 vhost 請求頁面。
如果請求中的 URI 是絕對 URI,且其主機名稱和連接埠與主伺服器或其中一個設定的虛擬主機相符且與客戶端傳送請求的位址和連接埠相符,則會移除 scheme/hostname/port 前置詞,且其餘的相對 URI 由對應的主伺服器或虛擬主機提供服務。如果它不符,則 URI 保持不變,且請求被視為代理請求。
ServerName
和 ServerAlias
檢查絕不會針對基於 IP 的虛擬主機執行。Host:
標頭欄位中的任何連接埠都不會用於比對程序期間。Apache 總是會使用客戶端傳送請求的實際連接埠。*
vhost)不符。換句話說,主伺服器僅會擷取未指定位址/連接埠組合的請求(除非有一個與該連接埠相符的 _default_
vhost)。VirtualHost
指令中指定 DNS 名稱,因為這樣會強制您的伺服器依賴 DNS 才能開機。此外,如果您無法控制所列所有網域的 DNS,則會構成安全威脅。您可以 在此處 找到更多相關資訊,以及接下來的兩個主題。ServerName
應始終設定每個 vhost。否則,每個 vhost 都需要進行 DNS 查詢。