Ускорение сайта через .htaccess
Файлом .htaccess на Apache можно заметно ускорить сайт без правки кода: настроить кэш статики в браузере, включить сжатие текстовых ответов, отдавать заранее сжатые файлы, подсказать браузеру, что грузить вперёд. Ниже — готовые блоки под каждую задачу: вставляйте в .htaccess в корне сайта, плейсхолдеры (пути, домены) замените на свои. При сомнениях прогоните файл через линтер /check/; собрать .htaccess из чекбоксов можно в генераторе. В конце — чеклист на 5 минут.
Главное правило производительности на уровне .htaccess: кэшировать статику надолго (но с версионированными именами), сжимать текст (но не уже сжатые форматы) и не тащить в .htaccess то, что относится к конфигу сервера (KeepAlive и прочее — см. раздел 6).
1. Кэш статики в браузере
При повторных визитах файлы берутся из локального кэша браузера — ноль запросов к серверу. Два механизма: mod_expires (просто, по MIME-типам) и Header set Cache-Control (гибко, по маскам файлов).
<IfModule mod_expires.c> ExpiresActive On ExpiresByType image/jpeg "access plus 1 year" ExpiresByType image/png "access plus 1 year" ExpiresByType image/webp "access plus 1 year" ExpiresByType image/svg+xml "access plus 1 year" ExpiresByType image/x-icon "access plus 1 year" ExpiresByType font/woff2 "access plus 1 year" ExpiresByType text/css "access plus 1 year" ExpiresByType application/javascript "access plus 1 year" ExpiresByType text/html "access plus 0 seconds" </IfModule>
<IfModule mod_headers.c> <FilesMatch "\.(jpe?g|png|webp|svg|ico|woff2?|css|js)$"> Header set Cache-Control "public, max-age=31536000, immutable" </FilesMatch> <FilesMatch "\.(html|htm)$"> Header set Cache-Control "no-cache, must-revalidate" </FilesMatch> </IfModule>
- Поменяли
style.css— а у посетителя год висит старая версия. Решение: версионируйте имя файла (app.8f3a.css), а не только содержимое;?v=2работает, но query-версии хуже кэшируются прокси. immutableставьте только на файлы, имя которых меняется при изменении содержимого.- HTML кэшировать надолго нельзя — иначе пользователь не увидит обновлений (
no-cache, must-revalidateилиaccess plus 0 seconds).
Разбор Cache-Control / Expires / ETag / Vary — справочник HTTP-заголовков; собрать чекбоксами — генератор (блок «Кэш статики»).
2. Сжатие текстовых ответов (gzip / Brotli)
HTML / CSS / JS / JSON / SVG сжимаются в 3–5 раз — самый дешёвый выигрыш по объёму трафика и времени загрузки.
<IfModule mod_deflate.c> AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css AddOutputFilterByType DEFLATE application/javascript application/x-javascript AddOutputFilterByType DEFLATE application/json application/xml AddOutputFilterByType DEFLATE application/rss+xml application/atom+xml AddOutputFilterByType DEFLATE image/svg+xml application/vnd.ms-fontobject font/ttf font/otf </IfModule>
<IfModule mod_brotli.c> AddOutputFilterByType BROTLI_COMPRESS text/html text/css application/javascript application/json image/svg+xml </IfModule>
- НЕ добавляйте в список
image/jpeg,image/png,image/webp,video/*,application/zip,application/pdf— они уже сжаты, выигрыша ноль, а CPU тратится. woff2тоже уже сжат (в отличие отttf/otf).mod_gzip— древний модуль Apache 1.3 / 2.0, не путать сmod_deflate; двойное сжатие (gzip поверх Brotli) недопустимо — используйте<IfModule>-обёртки или что-то одно.
Собрать чекбоксами — генератор (блок «GZIP»; там же блок «Отдавать WebP/AVIF» — отдавать современные форматы картинок через .htaccess, если рядом лежат .webp/.avif-версии).
3. ETag, Last-Modified и ответы 304
При повторном запросе браузер шлёт If-None-Match / If-Modified-Since; если файл не изменился, сервер отвечает 304 Not Modified без тела — экономит трафик. Apache по умолчанию ставит и ETag, и Last-Modified.
# упростить ETag — убрать inode (важно, если сайт на нескольких серверах) FileETag MTime Size # или вовсе отключить ETag и полагаться на Last-Modified + Cache-Control: # FileETag None
- ETag по умолчанию включает inode файла → на кластере / нескольких бэкендах ETag разных серверов не совпадают, браузер каждый раз перекачивает файл — ставьте
FileETag MTime SizeилиFileETag None. - Если статике уже выставлен
Cache-Control: max-age=…, immutable, условные запросы для неё всё равно не сработают (браузер не пойдёт на сервер до истеченияmax-age) — это нормально.
Подробнее про эти заголовки — справочник HTTP-заголовков → кэш.
4. Отдавать заранее сжатые файлы (.gz)
Если на этапе сборки / деплоя рядом с app.js кладёте app.js.gz — Apache может отдавать готовый .gz без сжатия на лету (экономия CPU, заметно для крупных бандлов). Продвинутый приём.
<IfModule mod_rewrite.c> RewriteEngine On # клиент поддерживает gzip и рядом есть непустой <файл>.gz — отдаём его RewriteCond %{HTTP:Accept-Encoding} \bgzip\b RewriteCond %{REQUEST_FILENAME}\.gz -s RewriteRule ^(.+)\.(css|js)$ $1.$2.gz [QSA,L] </IfModule> <IfModule mod_headers.c> <FilesMatch "\.css\.gz$"> Header set Content-Encoding gzip Header set Content-Type "text/css" </FilesMatch> <FilesMatch "\.js\.gz$"> Header set Content-Encoding gzip Header set Content-Type "application/javascript" </FilesMatch> </IfModule> Header append Vary Accept-Encoding
- Обязателен
Vary: Accept-Encoding— иначе прокси может отдать gzip-байты клиенту без поддержки gzip. - Следите, чтобы
mod_deflateне сжимал.gzповторно. - Это для статики, которую вы пересобираете при деплое, — не для динамики.
Проверить, что RewriteRule срабатывает на нужном URL, — RewriteRule-тестер.
5. Подсказки браузеру через заголовки (preload)
HTTP-заголовок Link: rel=preload говорит браузеру заранее начать грузить критичные ресурсы (CSS, шрифт), не дожидаясь парсинга HTML; X-DNS-Prefetch-Control разрешает заранее резолвить DNS внешних доменов.
<IfModule mod_headers.c> # заранее начать грузить критичные ресурсы Header add Link "</css/app.css>; rel=preload; as=style" Header add Link "</fonts/main.woff2>; rel=preload; as=font; type=font/woff2; crossorigin" # резолвить DNS внешних доменов заранее Header set X-DNS-Prefetch-Control "on" </IfModule>
preloadресурса, который не нужен в первые секунды, наоборот вредит — отнимает полосу у действительно нужного.as=fontтребуетcrossorigin, даже если шрифт с того же домена.- Не плодите десятки
Link rel=preload— это не «загрузить всё сразу».
Разбор заголовка Link и других контент-заголовков — справочник HTTP-заголовков → контент.
6. Что НЕ ускоряет (частые заблуждения)
KeepAlive On,KeepAliveTimeout,MaxKeepAliveRequests,EnableSendfile,Timeout,MaxRequestWorkers— это директивы конфига сервера / vhost; в.htaccessони дадут500 Internal Server Error(… not allowed here) или будут проигнорированы.- Добавлять
image/jpeg,image/png,image/webp,video/*вmod_deflate— трата CPU без выигрыша (см. раздел 2). Cache-Control: immutable(или большойmax-age) на HTML и JSON-API — пользователь застрянет на старой версии (см. раздел 1).- ETag с inode за балансировщиком — ломает кэш (см. раздел 3).
mod_pagespeedот Google — заброшен с 2018, в современных Apache не собирается; не закладывайтесь..htaccessчитается и парсится Apache на каждый запрос ко всем файлам в этом каталоге и выше — гигантский.htaccess(и тем более по копии в каждом подкаталоге) сам по себе замедляет; по возможности выносите правила в конфиг сервера сAllowOverride None.
Линтер /check/ предупреждает о части директив, которые в .htaccess не работают.
Подробно про мифы о производительности .htaccess (тормозит ли он на самом деле, замеры, как ускорить) — статья «.htaccess: мифы о производительности».
Собрать всё это одним блоком в один клик — генератор «производительность .htaccess».
7. Чеклист: ускорение за 5 минут
- Статика (картинки, шрифты, CSS / JS) кэшируется на год? — раздел 1, /headers/
- Имена ассетов версионируются (меняются при изменении содержимого)? — раздел 1
- gzip (или Brotli) включён для HTML / CSS / JS / JSON / SVG? — раздел 2, /generator/
- Картинки и видео НЕ сжимаются повторно (
mod_deflateбезimage/*)? — раздел 2, раздел 6 - HTML отдаётся с
no-cache, must-revalidate, а не сimmutable? — раздел 1 Vary: Accept-Encodingстоит, если используете предсжатые.gz-варианты? — раздел 4- В
.htaccessнетKeepAliveи прочих директив «из конфига сервера»? — раздел 6, /check/
8. Ссылки и инструменты
- Генератор .htaccess — блоки «Кэш статики», «GZIP» чекбоксами.
- Справочник HTTP-заголовков —
Cache-Control/Expires/ETag/Vary/Link. - Линтер .htaccess — найдёт ошибки и директивы, которые в
.htaccessне работают. - Рецепты .htaccess — готовые блоки кэша и gzip.
- Центр безопасности — соседний гид: защита файлов, доступ, hardening.
- Директивы mod_expires · mod_deflate / mod_filter · Справочник директив.