Apache HTTP 服务器版本 2.4
在 配置文件 中的指令可以应用于整个服务器,也可以限制为仅应用于特定目录、文件、主机或 URL。本文档介绍如何使用配置节容器或.htaccess
文件来更改其他配置指令的作用域。
相关模块 | 相关指令 |
---|---|
容器主要有两种类型。大多数容器会针对每个请求进行评估。封闭的指令仅适用于与容器匹配的请求。另一方面,<IfDefine>
、<IfModule>
和 <IfVersion>
容器仅在服务器启动和重启时进行评估。如果它们的条件在启动时为真,则封闭的指令将应用于所有请求。如果条件不为真,则封闭的指令将被忽略。
<IfDefine>
指令包含仅在 httpd
命令行上定义了适当参数时才应用的指令。例如,使用以下配置,只有在使用 httpd -DClosedForNow
启动服务器时,所有请求才会被重定向到另一个站点。
<IfDefine ClosedForNow> Redirect "/" "http://otherserver.example.com/" </IfDefine>
<IfModule>
指令非常类似,只是它包含仅在服务器中提供特定模块时才应用的指令。该模块必须在服务器中静态编译,或者必须动态编译,并且其 LoadModule
行必须在配置文件中更早。只有在需要配置文件在安装或未安装某些模块的情况下都能正常工作时,才应使用此指令。不应使用它来包含始终要工作的指令,因为它会抑制有关缺少模块的有用错误消息。
在以下示例中,MimeMagicFile
指令仅在 mod_mime_magic
可用时才应用。
<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"
。(请注意,即使在 Windows 中,也应始终使用正斜杠作为 Apache httpd 配置文件中的路径分隔符。)相反,网络空间是 Web 服务器提供的网站视图,也是客户端看到的视图。因此,网络空间中的路径 /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-status
的文件。
<Location "/server-status"> SetHandler server-status </Location>
为了拥有两个重叠的 URL,必须考虑评估某些节或指令的顺序。对于 <Location>
,这将是
<Location "/foo"> </Location> <Location "/foo/bar"> </Location>
另一方面,<Alias>
是反向映射的
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>
指令可以使用 C 标准库中 fnmatch
中的 shell 风格通配符。字符 "*" 匹配任何字符序列,"?" 匹配任何单个字符,而 "[*seq]" 匹配 *seq* 中的任何字符。"/" 字符不会被任何通配符匹配;它必须显式指定。
如果需要更灵活的匹配,每个容器都有一个正则表达式 (regex) 对应项 <DirectoryMatch>
、<FilesMatch>
和 <LocationMatch>
,它们允许使用与 Perl 兼容的 正则表达式 来选择匹配项。但是,请参阅下面有关配置合并的部分,了解使用正则表达式节将如何更改指令的应用方式。
更改所有用户目录配置的非正则表达式通配符节可能如下所示
<Directory "/home/*/public_html"> Options Indexes </Directory>
使用正则表达式节,我们可以一次拒绝访问多种类型的图像文件
<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>
内部使用)。命名部分的正则表达式对应物行为相同。
嵌套部分在合并后,会与相同类型的非嵌套部分合并。
<VirtualHost>
容器包含应用于特定主机的指令。当从同一台机器提供多个主机时,这很有用,每个主机都有不同的配置。有关更多信息,请参阅虚拟主机文档。
<Proxy>
和 <ProxyMatch>
容器仅将包含的配置指令应用于通过 mod_proxy
的代理服务器访问的网站,这些网站与指定的 URL 匹配。例如,以下配置将仅允许一部分客户端使用代理服务器访问www.example.com
网站
<Proxy "http://www.example.com/*"> Require host yournetwork.example.com </Proxy>
要了解在哪些类型的配置部分中允许哪些指令,请检查指令的上下文。在 <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>
可以提供帮助。.htaccess
中使用 <If>
时,父目录中包含的指令将在之后合并子目录中未包含的指令。Aliases
和DocumentRoots
将 URL 映射到文件名)之前,会执行一个<Location>
/<LocationMatch>
序列。转换完成后,此序列的结果将被完全丢弃。阅读配置部分如何合并后经常出现的一个问题是,如何以及何时处理特定模块(如 mod_rewrite
)的指令。答案并不简单,需要一些背景知识。每个 httpd 模块都管理自己的配置,并且它在 httpd.conf 中的每个指令都在特定上下文中指定一个配置片段。httpd 不会在读取时执行命令。
在运行时,httpd 的核心会按上述顺序迭代定义的配置部分,以确定哪些部分适用于当前请求。当第一个部分匹配时,它被认为是此请求的当前配置。如果后续部分也匹配,则每个在两个部分中都有指令的模块都有机会合并其配置。结果是第三个配置,此过程将一直持续到所有配置部分都被评估为止。
完成上述步骤后,HTTP 请求的“真实”处理将开始:每个模块都有机会运行并执行它们喜欢的任何任务。它们可以从 httpd 的核心检索自己的最终合并配置,以确定它们应该如何行动。
一个例子可以帮助可视化整个过程。以下配置使用 mod_headers
的 Header
指令来设置特定的 HTTP 标头。httpd 将为对/example/index.html
的请求在CustomHeaderName
标头中设置什么值?
<Directory "/"> Header set CustomHeaderName one <FilesMatch ".*"> Header set CustomHeaderName three </FilesMatch> </Directory> <Directory "/example"> Header set CustomHeaderName two </Directory>
Directory
"/" 匹配,并创建了一个初始配置,用于将CustomHeaderName
标头设置为值one
。Directory
"/example" 匹配,并且由于 mod_headers
在代码中指定了在合并时覆盖,因此将创建一个新的配置,用于将CustomHeaderName
标头设置为值two
。FilesMatch
".*" 匹配,并且出现了另一个合并机会,导致CustomHeaderName
标头被设置为值three
。mod_headers
,它将接收配置,将CustomHeaderName
标头设置为值three
。 mod_headers
通常使用此配置来执行其工作,即设置 foo 标头。这并不意味着模块不能执行更复杂的动作,例如丢弃不需要的或已弃用的指令等。这对 .htaccess 也是如此,因为它们在合并顺序中与 Directory
具有相同的优先级。要理解的重要概念是,配置部分(如 Directory
和 FilesMatch
)与模块特定指令(如 Header
或 RewriteRule
)不可比,因为它们在不同的级别上运行。
以下是人工示例,用于展示合并顺序。假设所有指令都适用于请求,则此示例中的指令将按以下顺序应用: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>
为了更具体地说明,请考虑以下情况。无论在 <Directory>
部分中设置了哪些访问限制,<Location>
部分将最后进行评估,并允许无限制地访问服务器。换句话说,合并顺序很重要,请谨慎操作!
<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>