.htaccess: мифы о производительности
Расхожее мнение: «.htaccess тормозит сайт — лучше его не использовать». Правда сложнее: для нормального небольшого файла оверхед микроскопический и в реальных условиях незаметен. Но несколько конкретных паттернов действительно замедляют — разберём каждый.
1. Правда ли .htaccess тормозит?
Короткий ответ: для нормального небольшого .htaccess — нет, оверхед микроскопический и на практике незаметен. Для гигантского файла, или если .htaccess лежит по копии в каждой подпапке, или если в начале правил стоит широкий catch-all .* — да, реальное замедление.
Миф живёт потому, что Apache читает .htaccess на каждый запрос — это правда. Но само по себе это ещё не значит «медленно»: ОС кэширует файл в памяти, и при маленьком .htaccess стоимость парсинга ничтожна. Проблема начинается при больших файлах или неудачной структуре правил.
2. Как Apache читает .htaccess
При каждом запросе Apache проходит путь от DocumentRoot вниз до каталога, где лежит запрошенный файл. В каждом каталоге на этом пути он проверяет, есть ли .htaccess, и если есть — читает и парсит его заново. Это означает:
- Запрос к
/blog/2024/post.html→ Apache читает.htaccessиз корня, из/blog/и из/blog/2024/, если они существуют. - Статика (CSS / JS / картинки) тоже проходит этот путь —
.htaccessчитается и на каждый хит по статике. - Правила в конфиге сервера (
<Directory>в vhost) парсируются один раз при старте Apache и живут в памяти.
Именно поэтому перенос правил в конфиг с AllowOverride None — самая радикальная оптимизация. Подробно о механизме — статья «AllowOverride и .htaccess vs httpd.conf».
3. Что реально медленно
- Гигантский
.htaccess— файл на сотни строк с десятками правил. Парсинг при каждом запросе начинает давать заметный оверхед. .htaccessв каждой подпапке — Apache суммирует работу по всем файлам на пути к запрошенному ресурсу. Три файла на пути — тройная стоимость парсинга.- Широкий catch-all
.*или(.+)в начале правил — такое правило проверяется на каждый запрос, включая статику. Если оно никогда не срабатывает — это лишняя работа впустую. Проверить тяжёлые правила — симулятор /perf-sim/. - Десятки
RewriteRuleбез раннего выхода — каждый запрос к статике прогоняется через все правила до конца. - Отсутствие раннего выхода для существующих файлов — без проверки
RewriteCond %{REQUEST_FILENAME} !-f/!-dзапрос к реально существующему файлу всё равно проходит все rewrite-правила.
4. Грубые ориентиры по замерам
- Пустой
.htaccessvs файл с 1000 строк правил — разница заметна: несколько миллисекунд на запрос при нагрузке. На небольшом трафике этого не увидите; на высоконагруженном — накапливается. - 10–20 правил — оверхед в пределах статистической погрешности на большинстве серверов.
- Статика (CSS / JS / картинки) — тоже читает
.htaccessпри каждом хите. Если статики много и она часто запрашивается — ранний выход для существующих файлов даёт реальный прирост. - ОС кэширует файл в памяти — дисковое чтение дешёвое; дорог именно парсинг при большом файле.
5. Как ускорить
① Перенести правила в конфиг сервера / vhost с AllowOverride None — самый эффективный шаг, если есть доступ к конфигу (VPS / выделенный сервер). Правила обрабатываются один раз при старте, а не при каждом запросе. Подробно: «AllowOverride и .htaccess vs httpd.conf».
<Directory /var/www/example.com/public_html> AllowOverride None Require all granted RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . index.php [L] </Directory>
② Не плодить .htaccess в подкаталогах — держите один файл в корне. Каждый лишний .htaccess на пути к файлу — дополнительный парсинг при каждом запросе.
③ Ранний выход для существующих файлов — добавьте в начало rewrite-блока условия, чтобы реальные файлы и каталоги не прогонялись через все правила:
RewriteEngine On # если файл или каталог реально существуют — не трогать (статика, etc.) RewriteCond %{REQUEST_FILENAME} -f [OR] RewriteCond %{REQUEST_FILENAME} -d RewriteRule ^ - [L] # остальные запросы — во фронт-контроллер RewriteRule . index.php [L]
④ <FilesMatch> вместо широких RewriteRule — для добавления заголовков к статике используйте <FilesMatch "\.(css|js|webp)$">, а не RewriteRule. <FilesMatch> эффективнее: Apache матчит имя файла один раз, без прохода по всем rewrite-правилам.
⑤ Убрать неиспользуемые и устаревшие директивы — «мёртвые» строки всё равно парсируются. Проверить файл: линтер /check/.
6. Мелкие мифы
Options -Indexesне замедляет — это просто флаг, устанавливаемый при парсинге; влияния на производительность ответа практически нет.- Много
Header setне тормозит — заголовки формируются Apache и так при каждом ответе; добавление нескольких строк черезmod_headersничтожно дёшево. mod_rewriteсам по себе быстрый — медленными делают его плохие правила: catch-all в начале, который проверяется на каждый запрос, но никогда не срабатывает.<IfModule>-обёртки почти бесплатны — проверка, загружен ли модуль, происходит один раз при парсинге и кэшируется..htaccessНЕ кэшируется Apache между запросами — именно поэтому он читается каждый раз. Но ОС кэширует содержимое файла в памяти, так что дисковое чтение обычно дёшево. Главная стоимость — парсинг текста при большом файле.
7. Чеклист
- ①
.htaccessне гигантский (до ~50 строк реальных директив)? - ② Нет копий
.htaccessв каждой подпапке — один в корне? - ③ Нет catch-all
.*или(.+)в самом начале правил? — проверьте симулятором /perf-sim/ - ④ Есть ранний выход для существующих файлов (
RewriteCond %{REQUEST_FILENAME} !-f/!-d)? - ⑤ Если есть доступ к конфигу сервера — правила перенесены туда с
AllowOverride None? — статья AllowOverride - ⑥ Нет мёртвых директив, которые Apache игнорирует или не поддерживает? — /check/
8. Ссылки и инструменты
- «Ускорение сайта через .htaccess» — кэш статики, gzip, ETag, preload.
- Симулятор нагрузки mod_rewrite — покажет тяжёлые правила, catch-all, сколько раз каждое правило срабатывает.
- «AllowOverride и .htaccess vs httpd.conf» — как перенести правила в конфиг сервера.
- Линтер .htaccess — находит мёртвые и устаревшие директивы.
- Объяснялка .htaccess — разбор файла построчно.
- Справочник директив — Core —
AllowOverride,Optionsи другие. - «.htaccess на разных хостингах» — где есть доступ к конфигу, где нет.