Apache HTTP Server 2.4 版
設定檔中的指令可以套用至整個伺服器,或者僅侷限於套用至特定的目錄、檔案、主機或 URL。本文件描述如何使用設定區段容器或 .htaccess
檔案來變更其他設定指令的範圍。
相關模組 | 相關指令 |
---|---|
有兩種基本類型的容器。多數容器會針對每一項要求進行評估。附帶的指令僅適用於與容器相符的那些要求。<IfDefine>
、<IfModule>
和<IfVersion>
容器反而只在伺服器啟動和重新啟動時評估。如果其條件在啟動時為真,那麼附帶的指令就會適用於所有要求。如果條件不成立,那麼附帶的指令就會被忽略。
<IfDefine>
指令包含會在 httpd
指令列中定義指定參數時才會套用的指令。例如,在以下組態的情況下,只有在使用 `httpd -DClosedForNow` 啟動伺服器時,才會將所有要求重新導向至另一個網站
<IfDefine ClosedForNow> Redirect "/" "http://otherserver.example.com/" </IfDefine>
<IfModule>
指令的作用很類似,但不同的地方是它會包含伺服器中存在特定模組時才會套用的指令。該模組必須在伺服器中靜態編譯,或是必須動態編譯,且其 LoadModule
列必須出現在組態檔案前面。只有當你需要組態檔案在某些模組已安裝或未安裝的狀況下都能運作時,才應該使用此指令。不應將你希望一直都能運作的指令包含在其中,因為這會抑制缺少模組相關的有用錯誤訊息。
在下例中,僅有在 mod_mime_magic
可用的情況下,MimeMagicFile
指令才會被套用。
<IfModule mod_mime_magic.c> MimeMagicFile "conf/magic" </IfModule>
<IfVersion>
指令的作用與 <IfDefine>
和 <IfModule>
很類似,但不同的地方是它會包含只有在特定版本的伺服器執行時才會套用的指令。此模組是針對需要處理不同 httpd 版本及不同組態的測試套件和大型網路所設計。
<IfVersion >= 2.4> # this happens only in versions greater or # equal 2.4.0. </IfVersion>
<IfDefine>
、<IfModule>
和 <IfVersion>
可在它們的測試前加「!」來套用負面條件。另外,這些區段可以巢狀,以達成更複雜的限制。
最常使用的組態區段容器是指那些會變更檔案系統或網路空間特定位置組態的容器。首先,理解兩者之間的差異十分重要。檔案系統是指你的作業系統視為磁碟的檢視方式。例如,在預設安裝中,Apache httpd 在 Unix 檔案系統中的位置為 /usr/local/apache2
,在 Windows 檔案系統中的位置為 "c:/Program Files/Apache Group/Apache2"
。(請注意,在 Apache httpd 組態檔案中,路徑分隔符號永遠都應該使用正斜線,即使是在 Windows 中。)相較之下,網路空間是指你的網站由網路伺服器傳輸並由用戶端檢視的方式。因此,網路空間中的路徑 /dir/
對應到 Unix 中預設安裝 Apache httpd 的檔案系統中的路徑 /usr/local/apache2/htdocs/dir/
。網路空間不一定要直接對應到檔案系統,因為網頁也可能從資料庫或其他位置動態產生。
指令 <Directory>
和 <Files>
,連同它們的 正規表示式 對應,套用指令至檔案系統的各個部分。包在 <Directory>
區段中的指令套用到指定的檔案系統目錄及該目錄的所有子目錄(以及這些目錄中的檔案)。使用 .htaccess 檔案 可以獲得相同的結果。例如,在以下設定檔中,會為 /var/web/dir1
目錄及其所有子目錄啟用目錄索引。
<Directory "/var/web/dir1"> Options +Indexes </Directory>
包在 <Files>
區段中的指令會套用到任何具有指定名稱的檔案,不論它位於哪一個目錄中。因此,例如,以下設定檔指令會在放置於設定檔檔的主區段中時,拒絕存取任何被命名為 private.html
的檔案,不論它位於何處。
<Files "private.html"> Require all denied </Files>
為了處理檔案在檔案系統中特定部分的發現,<Files>
和 <Directory>
區段可以結合使用。例如,以下設定檔將會拒絕存取 /var/web/dir1/private.html
、/var/web/dir1/subdir2/private.html
、/var/web/dir1/subdir3/private.html
,以及在 /var/web/dir1/
目錄下找到的任何其他 private.html
個體。
<Directory "/var/web/dir1"> <Files "private.html"> Require all denied </Files> </Directory>
反之,指令 <Location>
和它的 正規表示式 對應會變更網頁空間中內容的設定檔。例如,以下設定檔會防止存取任何由 /private 開始的 URL 路徑。特別是,它會套用到對於 http://yoursite.example.com/private
、http://yoursite.example.com/private123
和 http://yoursite.example.com/private/dir/file.html
的要求,以及任何其他以 /private
字串開始的要求。
<LocationMatch "^/private"> Require all denied </LocationMatch>
指令 <Location>
的功能不一定要和檔案系統有關。例如,以下範例顯示如何將特定的 URL 對應至由 mod_status
提供的內部 Apache HTTP Server 處理程式。不需要在檔案系統中建立稱為 server-status
的檔案。
<Location "/server-status"> SetHandler server-status </Location>
為了擁有兩個交疊的 URL,需要考慮某些區段或指令評估的順序。對於 <Location>
而言,這會是
<Location "/foo"> </Location> <Location "/foo/bar"> </Location>
另一方面,<Alias>
es 以相反方式對應
Alias "/foo/bar" "/srv/www/uncommon/bar" Alias "/foo" "/srv/www/common/foo"
這對於 ProxyPass
指令來說也是正確的
ProxyPass "/special-area" "http://special.example.com" smax=5 max=10 ProxyPass "/" "balancer://mycluster/" stickysession=JSESSIONID|jsessionid nofailover=On
指令 <Directory>
、<Files>
和 <Location>
都可以使用 shell 式樣通配符,就像 C 標準函式庫中的 `fnmatch`。字元「*」比對任何順序的字元、「?」比對任何單一字元,「[seq]」比對 seq 中的任何一個字元。任何通配符都不能比對到「/」字元,必須明確指定。
如果需要更彈性的比對,每個容器都有對應的正規表示法 (regex) <DirectoryMatch>
、<FilesMatch>
和 <LocationMatch>
,其允許使用與 perl 相容的 正規表示式 選擇比對結果。但在下方關於設定合併的區塊找到 regex 區塊將如何變動指令套用的方式。
非正規表示式通配符區塊變動所有使用者目錄設定如下所示
<Directory "/home/*/public_html"> Options Indexes </Directory>
使用 regex 區塊,我們可以一次拒絕存取許多類型的圖檔
<FilesMatch "\.(?i:gif|jpe?g|png)$"> Require all denied </FilesMatch>
加入命名群組和反向參照的正規表示式,其對應的名稱以大寫字母放入環境中。這麼做就能從 表示法 和 mod_rewrite
等模組參照檔案名稱路徑和 URL 的元素。
<DirectoryMatch "^/var/www/combined/(?<SITENAME>[^/]+)"> Require ldap-group "cn=%{env:MATCH_SITENAME},ou=combined,o=Example" </DirectoryMatch>
指令 <If>
根據一個布林表示式表達的條件變更設定,例如,下列設定拒絕存取除非 HTTP Referer 標頭開頭為「http://www.example.com/」的存取。
<If "!(%{HTTP_REFERER} -strmatch 'http://www.example.com/*')"> Require all denied </If>
在檔案系統容器和網路空間容器之間選擇其實很簡單。如果要在存在於檔案系統中的物件套用指令,請務必使用 <Directory>
或 <Files>
。如果要在不存在於檔案系統中的物件套用指令(例如由資料庫產生的網頁),請使用 <Location>
。
嘗試限制存取檔案系統中的物件時,務必不要使用 <Location>
。那是因為很多不同的網路空間位置 (URL) 可以對應到同一個檔案系統位置,你的限制就有可能遭到規避,例如考慮下列設定
<Location "/dir/"> Require all denied </Location>
如果要求為 http://yoursite.example.com/dir/
,這是可行的。但如果您的檔案系統不區分大小寫會如何?那麼只要提出 http://yoursite.example.com/DIR/
的要求,就能輕易繞過您的限制。相反地,<Directory>
指令將適用於從該位置提供的所有內容,無論如何呼叫它。(例外的是檔案系統連結。同一目錄可以用符號連結放置在檔案系統的不同部分。<Directory>
指令將會遵循符號連結,而不會重新設定路徑名稱。因此,為了獲得最高層級的安全性,符號連結應該透過適當的 Options
指令停用。)
如果您可能認為這一切不適用於您,因為您使用區分大小寫的檔案系統,請記住還有許多其他方式可以將多個網路空間位置對映到同一個檔案系統位置。因此,當您可以的時候,您應該始終使用檔案系統容器。不過,這個規則有一個例外。在 <Location "/">
區段中放置組態限制絕對是安全的,因為這個區段將套用於所有請求,而不管 URL 為何。
一些區段類型可以在其他區段類型內嵌套。一方面,<Files>
可以用在 <Directory>
內。另一方面,<If>
可以用在 <Directory>
、<Location>
,以及 <Files>
區段(但不能在另一個 <If>
內)。命名區段的 regex 對應項行為相同。
嵌套區段會在相同類型的非嵌套區段之後合併。
<VirtualHost>
容器涵蓋適用於特定主機的指令。當從同一台機器為多個主機提供服務時,針對每個主機有不同的組態,這時就有用。有關更多資訊,請參閱 虛擬主機文件。
<Proxy>
和 <ProxyMatch>
容器僅套用封閉的組態指令到透過符合指定 URL 的
代理程式存取的網站。例如,以下配置將只允許部分用戶端使用代理程式存取 mod_proxy
www.example.com
網站
<Proxy "http://www.example.com/*"> Require host yournetwork.example.com </Proxy>
要找出在哪些類型的組態區段中允許哪些指令,請檢查指令的 Context。在 <Directory>
區段中允許的所有內容在语法上也允許在 <DirectoryMatch>
、<Files>
、<FilesMatch>
、<Location>
、<LocationMatch>
、<Proxy>
和 <ProxyMatch>
區段中。但有一些例外
AllowOverride
指令僅在 <Directory>
區段中執行。FollowSymLinks
和 SymLinksIfOwnerMatch
Options
僅在 <Directory>
區段或 .htaccess
檔案中執行。Options
指令不能用在 <Files>
和 <FilesMatch>
區段。組態區段以非常特定的順序套用。由於這會對組態指令的詮釋方式造成重大影響,因此了解這一點的工作原理非常重要。
合併順序是
<Directory>
(正規表示式除外)和 .htaccess
同時執行(如果允許,.htaccess
會覆寫 <Directory>
)<DirectoryMatch>
(和 <Directory "~">
)<Files>
和 <FilesMatch>
同時執行<Location>
和 <LocationMatch>
同時執行<If>
區段,即使它們包含在任何前述的綱領中。一些重要的備註
<Directory>
之外,在每個群組中,區段會按照它們在組態檔中出現的順序處理。例如,對 /foo/bar 的請求比對 <Location "/foo/bar">
和 <Location "/foo">
(本例中的群組 4):兩個區段都會評估,但順序會按照它們在組態檔中的出現順序而定。<Directory>
(上述群組 1)會從最短的目錄元件處理到最長的元件。例如,<Directory "/var/web/dir">
會在 <Directory "/var/web/dir/subdir">
之前處理。<Directory>
區段套用至同一個目錄,它們會依組態檔案的順序處理。Include
指令包含的組態會視為位於包含檔中的Include
指令位置。<VirtualHost>
區段內的區段會套用於對應的虛擬主機定義**外部**區段**之後**。這讓虛擬主機可以覆寫主伺服器組態。mod_proxy
提供服務時,<Proxy>
容器會取代<Directory>
容器的處理順序。<If>
內部和外部混合相關組態指令時,應格外小心,因為這會影響合併順序。明確使用<Else>
會有幫助。<If>
用於.htaccess
時,父目錄中包含的指令會在子目錄中非包含的指令**之後**合併。別名
和文件根目錄
用於將 URL 對應至檔案名稱)之前執行<Location>
/<LocationMatch>
順序。轉換完成後,這個順序的結果會被完全捨棄。在閱讀完組態區段的合併方式後,常會有一個問題會出現,即像mod_rewrite
這類特定模組的指令會在何時和如何處理。解答並非三言兩語可說明,而且需要一點背景知識。每個httpd模組會管理自己的組態,而每個模組在httpd.conf中的指令在特定脈絡中會設定組態的一部分。httpd並不會在讀取時執行指令。
在執行時期,httpd核心會依上述順序檢視定義的組態區段,以確定哪些適用于目前的請求。當找到第一個相符的區段時,就會將其視為此請求目前的組態。如果也有後續的區段相符,則無論指令在哪個區段中,每個模組都會有機會合併兩個區段中的組態。結果會成為第三個組態,這個程序會一直持續到評估完所有組態區段。
在完成上述步驟後,HTTP請求就會開始「真正」處理:每個模組都有機會執行和執行各種任務。它們可以從httpd核心取得自己最後合併的組態,以決定它們應該如何作用。
一個範例有助於視覺化整個流程。以下設定使用 標頭
指令的 mod_headers
來設定一個特定的 HTTP 標頭。對於對 `example/index.html` 的要求,httpd 將在 `CustomHeaderName` 標頭中設定什麼值?
<Directory "/"> Header set CustomHeaderName one <FilesMatch ".*"> Header set CustomHeaderName three </FilesMatch> </Directory> <Directory "/example"> Header set CustomHeaderName two </Directory>
目錄 "/" 匹配並建立初始設定來將 `CustomHeaderName` 標頭設定為值 `one`。
目錄
"/example" 匹配,由於 mod_headers
在其程式碼中指定在合併的情況下覆寫,建立一個新的設定來將 `CustomHeaderName` 標頭設定為值 `two`。檔案相符
".*" 匹配並出現另一個合併機會,導致 `CustomHeaderName` 標頭被設定為值 `three`。mod_headers
將會被呼叫,它將收到設定來將 `CustomHeaderName` 標頭設定為值 `three`。 mod_headers
通常使用此設定來執行任務,也就是設定 foo 標頭。這不表示一個模組無法執行一個更複雜的動作,例如拋棄指令,因為不必要或過時,等等。這對於 .htaccess 也是事實,因為它們與 目錄 在合併順序上有相同的優先順序。要了解的重要概念是,像
目錄
和 檔案相符
之類的設定區段與像 標頭
或 重寫規則
之類的模組特定指令不可比擬,因為它們運作在不同的層級。
以下是一個顯示合併順序的人工範例。假設它們都套用在要求上,此範例中的指令會以順序 A > B > C > D > E 套用。
<Location "/"> E </Location> <Files "f.html"> D </Files> <VirtualHost *> <Directory "/a/b"> B </Directory> </VirtualHost> <DirectoryMatch "^.*b$"> C </DirectoryMatch> <Directory "/a/b"> A </Directory>
對於一個更具體的範例,考量以下內容。無論任何存取限制設在哪些
區段中,
區段會最後評估,並會允許不受限制地存取伺服器。換句話說,合併的順序很重要,所以請小心!
<Location "/"> Require all granted </Location> # Whoops! This <Directory> section will have no effect <Directory "/"> <RequireAll> Require all granted Require not host badguy.example.com </RequireAll> </Directory>