Разделы конфигурации
Директивы в файлах конфигурации могут применяться ко всему серверу или быть ограничены определёнными каталогами, файлами, хостами или 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 находится по адресу /usr/local/apache2 в файловой системе Unix или "c:/Program Files/Apache Group/Apache2" в файловой системе Windows. (Обратите внимание: в файлах конфигурации Apache httpd в качестве разделителя пути всегда следует использовать прямую косую черту, даже в Windows.) Веб-пространство, напротив, — это представление сайта, которое формируется веб-сервером и отображается клиенту. Поэтому путь /dir/ в веб-пространстве соответствует пути /usr/local/apache2/htdocs/dir/ в файловой системе при установке Apache httpd по умолчанию в Unix. Веб-пространство не обязательно напрямую соответствует файловой системе, поскольку веб-страницы могут динамически формироваться из баз данных или других источников.
Контейнеры файловой системы
Директивы <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 и любому другому экземпляру private.html, найденному в каталоге /var/web/dir1/.
<Directory "/var/web/dir1">
<Files "private.html">
Require all denied
</Files>
</Directory> Контейнеры веб-пространства
Директива <Location> и её аналог с регулярным выражением, напротив, изменяют конфигурацию для содержимого веб-пространства. Например, следующая конфигурация запрещает доступ к любому URL-пути, начинающемуся с /private. В частности, она будет применяться к запросам для 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 с внутренним обработчиком Apache HTTP Server, предоставляемым mod_status. Файл с именем 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> можно использовать подстановочные знаки в стиле оболочки, как в fnmatch из стандартной библиотеки C. Символ «*» соответствует любой последовательности символов, «?» — любому отдельному символу, а «[seq]» — любому символу из seq. Символ «/» не соответствует ни одному подстановочному знаку; его необходимо указывать явно.
Если требуется более гибкое сопоставление, для каждого контейнера есть аналог с регулярным выражением: <DirectoryMatch>, <FilesMatch> и <LocationMatch>. Они позволяют использовать совместимые с Perl регулярные выражения для выбора совпадений. Однако ознакомьтесь с разделом ниже об объединении конфигурации, чтобы узнать, как использование разделов с регулярными выражениями меняет порядок применения директив.
Раздел с подстановочными знаками, не использующий регулярные выражения и изменяющий конфигурацию для всех пользовательских каталогов, может выглядеть так:
<Directory "/home/*/public_html">
Options Indexes
</Directory> С помощью разделов с регулярными выражениями можно сразу запретить доступ ко многим типам файлов изображений:
<FilesMatch "\.(?i:gif|jpe?g|png)$">
Require all denied
</FilesMatch> Регулярные выражения, содержащие именованные группы и обратные ссылки, добавляются в окружение под соответствующими именами в верхнем регистре. Это позволяет ссылаться на элементы путей к файлам и URL из выражений и таких модулей, как mod_rewrite.
<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иSymLinksIfOwnerMatchOptionsработают только в разделах<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, заключённые в него директивы родительского каталога будут объединены после директив подкаталога, не заключённых в контейнер.
Техническое примечание
На самом деле непосредственно перед этапом преобразования имени (на которомAliases и DocumentRoots используются для сопоставления URL с именами файлов) выполняется последовательность <Location>/<LocationMatch>. Результаты этой последовательности полностью отбрасываются после завершения преобразования. Взаимосвязь модулей и разделов конфигурации
После знакомства с порядком объединения разделов конфигурации часто возникает вопрос о том, как и когда обрабатываются директивы отдельных модулей, таких как mod_rewrite. Ответ не так прост и требует небольшого пояснения. Каждый модуль httpd управляет собственной конфигурацией, а каждая его директива в httpd.conf задаёт одну часть конфигурации в определённом контексте. httpd не выполняет команду в момент её чтения.
Во время выполнения ядро httpd перебирает определённые разделы конфигурации в описанном выше порядке, чтобы определить, какие из них применяются к текущему запросу. Когда совпадает первый раздел, он считается текущей конфигурацией для этого запроса. Если совпадает и следующий раздел, каждому модулю, директива которого присутствует хотя бы в одном из этих разделов, предоставляется возможность объединить конфигурацию из двух разделов. В результате получается третья конфигурация, и процесс продолжается до тех пор, пока не будут обработаны все разделы конфигурации.
После этого начинается «реальная» обработка HTTP-запроса: каждый модуль получает возможность выполнить необходимые ему задачи. Чтобы определить, как действовать, модули могут получить из ядра httpd собственную итоговую объединённую конфигурацию.
Пример поможет наглядно представить весь процесс. В следующей конфигурации директива Header модуля mod_headers задаёт определённый HTTP-заголовок. Какое значение httpd установит в заголовке CustomHeaderName для запроса к /example/index.html ?
<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. - В конечном итоге, на следующих этапах обработки HTTP-запроса будет вызван
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>
© 2018 The Apache Software Foundation
Licensed under the Apache License, Version 2.0.
https://httpd.apache.org/docs/2.4/en/sections.html