.htaccess: полная инструкция для Apache

8 ноября 2026 г.

Положили .htaccess в корень сайта, прописали редирект на HTTPS, а вместо сайта открылась страница «Internal Server Error». Или наоборот: файл лежит на сервере неделями, а ничего не меняется. Обе ситуации объясняются тем, что .htaccess работает только под Apache, только при определённых настройках сервера и только с включёнными модулями.

Что такое .htaccess и когда он применяется

.htaccess это файл конфигурации Apache, который читается при обработке запроса к директории и применяется к этой директории и всем вложенным. Он существует специально для случаев, когда у пользователя нет доступа к главному конфигурационному файлу сервера httpd.conf: на виртуальном хостинге, на обычном shared-хостинге, в панелях управления вроде cPanel.

Здесь важно не перепутать серверные технологии. Файл читают Apache и совместимые с ним серверы, LiteSpeed в частности. Nginx его полностью игнорирует: там синтаксис другой, правила описываются в блоках server и location, и файл с тем же именем просто лежит мёртвым грузом. Если сайт обслуживает Nginx, настройки редиректов и заголовков ищут в конфигурации самого Nginx, а не в .htaccess.

Второе важное ограничение связано с тем, что Apache по умолчанию вообще не смотрит в эти файлы. За это отвечает директива AllowOverride в конфигурации сервера, и значение по умолчанию равно None. В таком режиме .htaccess полностью игнорируется, и никакие правки в нём не дадут эффекта.

Отдельно стоит сказать про производительность. Главный конфиг сервера читается один раз при старте. Файлы .htaccess проверяются при каждом запросе, причём Apache поднимается по дереву каталогов и ищет их на каждом уровне, пока не найдёт корень документа. Для страницы из /www/htdocs/example это означает проверку /.htaccess, /www/.htaccess, /www/htdocs/.htaccess и /www/htdocs/example/.htaccess. Даже если файлов нет, сам обход дерева и лишние обращения к файловой системе остаются. Если есть доступ к httpd.conf, разумнее писать правила там.

Где лежит файл и как работает наследование

Файл называется .htaccess и лежит в директории, к которой применяется. Его можно переименовать, если в httpd.conf задана директива AccessFileName, но по умолчанию имя фиксировано.

Правила наследуются сверху вниз. Файл в корне документа действует на весь сайт, файл в подпапке добавляет свои правила поверх родительских и может их переопределить. При этом некоторые директивы переопределяются полностью, а не дополняются. Классический пример: Options в дочерней директории полностью заменяет родительский, а не дополняет его.

Дерево директорий и наследование
/.htaccess                    правила для всего сервера
/www/.htaccess                правила для /www
/www/htdocs/.htaccess         правила для всего сайта
/www/htdocs/example/.htaccess правила для раздела example

Запрос к /www/htdocs/example/page.html обрабатывают все четыре файла.

Чтобы проверить, читает ли сервер файлы .htaccess вообще, есть простой приём. Положите в директорию заведомо несуществующую директиву и посмотрите на реакцию сервера.

Проверка: сервер читает .htaccess или игнорирует
# положить во временный файл и запросить любую страницу
TestMe

Ответ 500 и запись в логе ошибок → .htaccess читается, директива незнакома
Обычный ответ 200            → AllowOverride None, файл полностью игнорируется

AllowOverride: без него файл не работает

В httpd.conf есть блок Directory, и в нём указывается, какие категории директив разрешено переопределять из .htaccess. Значение по умолчанию None означает, что файлы не читаются вообще.

Разрешение править RewriteRule и Redirect из .htaccess
<Directory "/var/www/example">
    AllowOverride FileInfo AuthConfig Indexes
    AllowOverrideList Redirect RedirectMatch RewriteEngine RewriteRule RewriteCond
</Directory>

Разрешённые категории работают следующим образом. Options разрешает директиву Options. FileInfo открывает доступ к AddType, AddHandler и SetHandler. AuthConfig позволяет менять настройки авторизации. Indexes разрешает DirectoryIndex. All разрешает всё сразу, и это наименее безопасный вариант. Более тонкая настройка возможна через AllowOverrideList, где перечисляются конкретные директивы: директива, не попавшая в список, вызовет ошибку сервера.

RewriteEngine и RewriteRule: главный рабочий механизм

Модуль mod_rewrite отвечает за преобразование адресов, и в .htaccess он используется постоянно. Работает он так: сначала включается движок директивой RewriteEngine On, затем описываются правила RewriteRule, а при необходимости и условия RewriteCond, которые проверяются перед основным правилом.

Правило состоит из шаблона, цели и флагов. Шаблон это регулярное выражение, цель это адрес или путь, а флаги задают дополнительное поведение. Самые ходовые: L означает прекратить обработку текущего набора правил, R означает редирект с указанным кодом, F отдаёт 403, а QSA добавляет к новому адресу исходную строку запроса.

Типовые редиректы
# включить движок (обязательно)
RewriteEngine On

# 301 с любого адреса на главную, кроме самого /
RewriteRule ^$ /index.html [L]

# редирект со старого пути на новый
RewriteRule ^old-page/(.*)$ /new-page/$1 [R=301,L]

# 404 для несуществующего файла
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /404.html [L]

Здесь есть тонкость, на которой спотыкаются чаще всего. В .htaccess правила работают в контексте текущей директории: из адреса убирается префикс, соответствующий этой директории. Поэтому шаблон, который в httpd.conf записывается как ^/images/(.+).jpg, в .htaccess в корне сайта записывается как ^images/(.+).jpg, а в директории images/ вообще как ^(.+).jpg. Ещё одна особенность: регулярные выражения в .htaccess перекомпилируются при каждом запросе, тогда как в главном конфиге они компилируются один раз и кэшируются. Разобрать адрес на части и увидеть, какой путь увидит правило, помогает парсер URL.

Отдельно про порядок выполнения. Сначала проверяются условия RewriteCond, причём все условия группы должны быть истинны. Затем применяется RewriteRule. Если условие не выполнилось, правило пропускается и Apache идёт дальше по конфигурации.

Без RewriteBase в поддиректории с относительными адресами не обойтись. Директива задаёт базовый URL, к которому привязываются результаты подстановок. Если в .htaccess лежит правило, которое переписывает адрес в новый путь, и этот файл находится не в корне, без RewriteBase результат подстановки будет вести в никуда.

Redirect, ErrorDocument, DirectoryIndex и другие директивы

Не всё в .htaccess делается через mod_rewrite. Часть директив работает сама по себе, и для многих задач они удобнее.

  • Redirect permanent /old /new делает постоянный редирект, а Redirect 302 /temporary /target временный. Работает на уровне модулей Apache и не требует mod_rewrite;
  • RedirectMatch задаёт шаблон адреса регулярным выражением, что удобно для массовых редиректов по разделам;
  • ErrorDocument 404 /errors/404.html подменяет стандартную страницу ошибки своей. Работает для кодов 400, 401, 403, 404, 500 и других;
  • DirectoryIndex index.php index.html задаёт порядок поиска файла-заглушки при обращении к директории;
  • AddType application/json .json привязывает к расширению тип содержимого, который сервер иначе не отдаёт правильно;
  • Options -Indexes запрещает листинг содержимого директории, а Options +FollowSymLinks разрешает символические ссылки;
  • SetEnv и RewriteRule с флагом ENV позволяют передавать переменные окружения дальше по цепочке обработки.
Страница ошибки, запрет листинга, типы и сжатие
ErrorDocument 404 /404.html
ErrorDocument 500 /500.html

Options -Indexes
Options +FollowSymLinks

AddType application/json .json
AddType image/svg+xml .svg

<IfModule mod_deflate.c>
  AddOutputFilterByType DEFLATE text/html text/css application/javascript application/json
</IfModule>

Блоки вида <IfModule mod_rewrite.c> стоит добавлять всегда. Если модуль не загружен, содержимое блока просто пропускается, и сайт продолжает работать. Без такой защиты любая директива из отсутствующего модуля приводит к ошибке 500 на каждый запрос к директории. Типы содержимого, которые задаёт AddType, стоит заранее сверить с таблицей: справочник MIME-типов показывает, какой тип отдаётся сервером для конкретного расширения по умолчанию.

Доступ к папкам: Require, Deny и пароли

Закрыть директорию от посторонних можно несколькими способами, и разница между ними существенная.

В Apache 2.4 доступ регулируется директивой Require, которая пришла на смену связке Order, Allow и Deny из версии 2.2. Конструкция Require all denied закрывает всё, Require all granted открывает всё, а Require ip ограничивает по адресу, в том числе в виде подсети или диапазона. Если переносите конфигурацию с 2.2, то Order deny,allow и Allow from 192.168.1.0/24 превращаются в Require ip 192.168.1.0/24, а связка Deny from all с Allow from 192.168.1.0/24 превращается в Require ip 192.168.1.0/24.

Закрыть папку по IP и по паролю
# закрыть по IP (Apache 2.4)
<Files "secret.txt">
    Require ip 192.168.1.0/24
</Files>

# закрыть по паролю (htpasswd)
AuthType Basic
AuthName "Restricted area"
AuthUserFile /var/www/.htpasswd
Require valid-user

Для парольной защиты нужен файл с учётными записями, который создаётся утилитой htpasswd. Пароли в нём хранятся в виде хэшей, а не открытым текстом, но сам механиз Basic передаёт пароль по сети, поэтому такая защита годится только внутри HTTPS.

В директивах Allow и Deny, если они всё же используются, порядок строк определяет логику, и это постоянный источник ошибок. Строка Order deny,allow означает, что сначала проверяются запреты, потом разрешения, и Deny from all перекрывает Allow from all, если стоит раньше. В Require такой двусмысленности нет.

Заголовки, сроки жизни и php_value

Модуль mod_headers позволяет управлять ответами сервера, а с его помощью настраивают то, что иначе приходится делать кодом.

Заголовки и кэширование
<IfModule mod_headers.c>
  # принудительный HTTPS
  Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"

  # запрет кэширования для API
  <FilesMatch "\.json$">
    Header set Cache-Control "no-store"
  </FilesMatch>
</IfModule>

<IfModule mod_expires.c>
  ExpiresActive On
  ExpiresByType text/css "access plus 1 year"
  ExpiresByType image/svg+xml "access plus 1 year"
</IfModule>

Директива php_value меняет значения конфигурации PHP прямо из .htaccess, и работает только при использовании модуля mod_php. На серверах с PHP-FPM она недоступна, и значения задаются через php.ini или файл .user.ini в директории. Там, где php_value применён не к тому модулю, Apache отдаёт ошибку 500.

Ошибка 500: как найти причину

Пустой ответ с кодом 500 после загрузки файла это самая частая реакция на неправильный .htaccess. Причин три, и все три проверяются в логе ошибок сервера.

  • директива не разрешена настройками AllowOverride. В логе это выглядит как сообщение о том, что директива здесь недопустима, и означает ровно то, что написано;
  • синтаксическая ошибка в самой директиве, например неверный разделитель флагов в RewriteCond;
  • модуль, который предоставляет директиву, не загружен. Для RewriteRule это mod_rewrite, и тогда в логе появляется сообщение о неизвестной или недопустимой директиве.

Проверка на живом сервере выглядит так: убедиться, что модуль загружен командой apachectl -M | grep rewrite, затем посмотреть лог ошибок, где для каждой сбойной директивы указана причина и номер строки. Разбор файла на синтаксис до загрузки на сервер можно сделать отдельно, положив содержимое в отдельную директорию и запросив её. Сами регулярные выражения из шаблонов RewriteRule стоит проверить заранее: тестировщик регулярных выражений показывает, что именно ловит шаблон и что он пропускает.

Типичные ошибки

  • редирект, который перенаправляет сам себя. Классический случай, когда RewriteRule ловит адрес, в который только что отправил посетителя, и цикл заканчивается ошибкой «too many redirects»;
  • забытый RewriteEngine On. Без него правила просто не выполняются, и это выглядит как «файл лежит, но ничего не делает»;
  • пробелы в регулярном выражении. В шаблоне пробел означает буквальный пробел, и строка с лишним пробелом не совпадёт ни с одним адресом;
  • неверный контекст шаблона. Паттерн с ведущим слешем в .htaccess не сработает, потому что префикс директории уже срезан;
  • mod_rewrite без RewriteBase в поддиректории, из-за чего подстановки ведут не туда;
  • кодировка. Если в правилах есть кириллица, а файл сохранён в windows-1251, то сервер может разобрать его как-то иначе; надёжное решение, это UTF-8 без BOM;
  • смешение Allow и Deny с Order, где порядок строк меняет смысл правила;
  • php_value на сервере с PHP-FPM, где такая директива неизвестна и роняет сайт.

Частые вопросы

Работает ли .htaccess на Nginx?

Нет, и это самая распространённая причина разочарования. Nginx не читает эти файлы вообще: он ищет конфигурацию в своём каталоге и читает её при старте. Правила для Nginx пишутся в блоках server и location, синтаксис там другой. Если hosting сообщает, что сервер работает на Nginx, искать настройки надо в конфиге Nginx, а настройки PHP в .htaccess работать не будут.

Почему сервер отдаёт 500 на мой .htaccess?

Смотрите лог ошибок: он прямо называет причину. Чаще всего это неизвестная директива из неподключённого модуля, синтаксическая ошибка или запрет на уровне AllowOverride. Чтобы сузить область поиска, разделите файл на части и загружайте по одной, либо закомментируйте всё, кроме заведомо рабочего блока, и добавляйте правила по одному.

Чем .htaccess отличается от конфига сервера?

Функционально почти ничем: те же директивы, тот же модуль mod_rewrite. Разница в подходе и в скорости. Правила в httpd.conf читаются один раз при старте и работают быстрее, в .htaccess файл проверяется при каждом запросе, а регулярные выражения перекомпилируются каждый раз. Зато .htaccess можно положить и убрать, не перезагружая сервер, и не нужно быть администратором.

Как закрыть папку от посетителей?

Способ зависит от задачи. Чтобы папку не было видно в списке, хватит Options -Indexes. Чтобы закрыть конкретный файл или каталог по IP, используйте Require ip или Require all denied. Для парольной защиты понадобится AuthType Basic с файлом AuthUserFile, созданным утилитой htpasswd, и обязательно HTTPS поверх, потому что Basic передаёт пароль в открытом виде.

Нужно ли перезагружать сервер после правки?

Нет, в этом и преимущество .htaccess: изменения применяются при следующем запросе к директории. Но есть исключение. При изменении AllowOverride в httpd.conf или при загрузке нового модуля сервер нужно перезапустить, потому что это настройки уровня сервера, а не уровня директории. Проверить, какой модуль загружен, можно командой apachectl -M.

Можно ли закрыть сайт от конкретного робота через .htaccess?

Да, через Require ip или Require not ip, если известен адрес бота. Это работает точнее, чем правила в robots.txt, о которых шла речь в статье про файл robots.txt и его директивы, потому что опирается на реальный адрес подключения, а не на имя, которое робот заявляет в заголовке User-Agent. Разобрать заголовок и понять, кто именно пришёл, помогает парсер User-Agent, а адреса и коды ответов удобно проверить через справочник HTTP-кодов.

Порядок работы, который экономит часы: сначала соберите готовый файл в генераторе, потом проверьте его на локальном Apache с включённым mod_rewrite, и только потом кладите на боевой сервер. Ошибку в синтаксисе намного дешевле поймать в тестовой директории, чем в корне сайта с записью в лог на каждом запросе.

Читайте также