Скорость сайта

Кэширование браузером через .htaccess: готовая конфигурация

Готовый блок mod_expires и mod_headers для статических ресурсов сайта на Apache. Cache-control на год для CSS, JS, шрифтов и картинок.

обновлено 8 минут чтения 0 Дмитрий Акиндинов
Содержание
  1. Зачем браузерный кеш
  2. Что кешировать и на сколько
  3. Готовая конфигурация .htaccess
  4. Что делает immutable
  5. Сжатие через mod_deflate
  6. Что НЕ кешировать
  7. Проверка работы кеша
  8. Особенности для WordPress
  9. Особенности для Битрикса
  10. Особенности для shared-хостинга
  11. Как обновлять файлы при кеше
  12. Что делать после установки
  13. Чек-лист правильной настройки
  14. Когда стоит делегировать
  15. Частые вопросы

Браузерный кэш ускоряет повторные заходы и снимает 200-500 мс с отрисовки. Настраивается одним блоком в .htaccess: год для картинок, шрифтов, CSS и JS с версионированием, 5-15 минут для HTML. Без версионирования в имени файла длинный кэш ставить нельзя.

Браузерный кеш это самый дешёвый способ ускорить сайт для повторных посетителей. Один правильный блок в .htaccess отдаёт на каждом ответе заголовок Cache-Control: max-age=31536000, и при следующем заходе браузер не идёт за CSS, JS, картинками на сервер. LCP опускается на 200-500 миллисекунд, нагрузка на хостинг падает в разы.

Но многие сайты в 2026 году по-прежнему отдают статику с заголовком Cache-Control: no-cache или max-age=0, и каждый посетитель скачивает всё заново. Разберу готовую рабочую конфигурацию для Apache shared-хостинга и что в ней важно.

Папка с файлами и значком часов

Зачем браузерный кеш

Когда браузер загружает страницу, он скачивает HTML, CSS, JS, картинки, шрифты. Если все эти файлы пометить Cache-Control: max-age=31536000 (год), браузер сохраняет копию у себя.

При следующем посещении той же страницы: — HTML может качаться заново (он часто меняется). — CSS, JS, картинки, шрифты браузер берёт из кеша. Запросов к серверу нет.

Что это даёт: — Скорость первой и второй страницы. На повторных переходах LCP падает до 0.5-1 секунды. — Меньше нагрузки на хостинг (и меньше расходов на трафик). — Лучше для пользователя на медленной сети: повторное открытие моментально.

Кеш не помогает первому посещению. Тут работают другие оптимизации (CDN, сжатие, минификация). Браузерный кеш для постоянной аудитории.

Что кешировать и на сколько

Принцип: то, что меняется редко, кешируем надолго. То, что часто, недолго или не кешируем.

Тип файлаСрок кешаКомментарий
Шрифты (.woff2)1 годМеняются почти никогда
Картинки (.jpg, .png, .webp, .avif, .svg)1 годЕсли используете хеш в имени
CSS, JS1 годПри условии хеша в имени
Видео1 год
Иконки favicon7-14 днейИногда меняется
HTML5-15 минут или без кешаЧасто обновляется
API-ответыбез кешаДинамические данные

Главное условие для долгого кеша: имя файла должно меняться при изменении содержимого. Если у вас style.css, и вы его правите, браузер всё равно будет показывать старый кеш. Решение это style.abc123.css, где abc123 меняется при каждой сборке.

Большинство современных сборщиков (Vite, Webpack, Astro, Next.js) делают это автоматически. На WordPress зависит от плагина: WP Rocket, Autoptimize и подобные ставят хеши в имена сжатых файлов.

Готовая конфигурация .htaccess

Базовая рабочая версия:

# Включаем модули
<IfModule mod_expires.c>
  ExpiresActive On
  ExpiresDefault "access plus 1 month"

  # Картинки
  ExpiresByType image/jpeg "access plus 1 year"
  ExpiresByType image/png "access plus 1 year"
  ExpiresByType image/webp "access plus 1 year"
  ExpiresByType image/avif "access plus 1 year"
  ExpiresByType image/gif "access plus 1 year"
  ExpiresByType image/svg+xml "access plus 1 year"
  ExpiresByType image/x-icon "access plus 1 week"
  
  # Шрифты
  ExpiresByType font/woff "access plus 1 year"
  ExpiresByType font/woff2 "access plus 1 year"
  ExpiresByType application/font-woff "access plus 1 year"
  ExpiresByType application/font-woff2 "access plus 1 year"
  
  # CSS и JS
  ExpiresByType text/css "access plus 1 year"
  ExpiresByType application/javascript "access plus 1 year"
  ExpiresByType text/javascript "access plus 1 year"
  
  # Видео
  ExpiresByType video/mp4 "access plus 1 year"
  ExpiresByType video/webm "access plus 1 year"
  
  # HTML и API: короткий кеш
  ExpiresByType text/html "access plus 5 minutes"
  ExpiresByType application/json "access plus 0 seconds"
  ExpiresByType application/xml "access plus 0 seconds"
</IfModule>

# Заголовок Cache-Control с immutable для статики с хешем
<IfModule mod_headers.c>
  <FilesMatch ".(jpg|jpeg|png|webp|avif|gif|svg|woff2|woff|css|js|mp4|webm)$">
    Header set Cache-Control "public, max-age=31536000, immutable"
  </FilesMatch>
  
  # HTML без длинного кеша
  <FilesMatch ".(html|htm)$">
    Header set Cache-Control "public, max-age=300, must-revalidate"
  </FilesMatch>
  
  # API-ответы не кешируются
  <FilesMatch ".(json|xml)$">
    Header set Cache-Control "no-cache, no-store, must-revalidate"
    Header set Pragma "no-cache"
    Header set Expires "0"
  </FilesMatch>
</IfModule>

Кладёте в public_html/.htaccess. Через минуту, без перезапуска Apache, правила работают.

Что делает immutable

Заголовок Cache-Control: public, max-age=31536000, immutable это идеальная комбинация для статики с хешем в имени.

public означает кеш можно держать в любом промежуточном кеше (CDN, прокси).

max-age=31536000 это 1 год в секундах.

immutable говорит браузеру, что файл не меняется. Это значит, что даже при Reload (Ctrl+R) браузер не идёт за файлом проверять. Файл всегда из кеша.

Это безопасно ровно потому, что у файла хеш в имени. Если нужно поменять CSS, имя поменяется (style.def456.css), и страница укажет на новый файл.

immutable поддерживается всеми современными браузерами с 2018-го.

Сжатие через mod_deflate

Кеширование работает в паре со сжатием. Сжатый файл занимает меньше места, поэтому его быстрее качать первым посетителям.

Добавляем к .htaccess:

<IfModule mod_deflate.c>
  AddOutputFilterByType DEFLATE text/html
  AddOutputFilterByType DEFLATE text/plain
  AddOutputFilterByType DEFLATE text/xml
  AddOutputFilterByType DEFLATE text/css
  AddOutputFilterByType DEFLATE application/javascript
  AddOutputFilterByType DEFLATE application/json
  AddOutputFilterByType DEFLATE application/xml
  AddOutputFilterByType DEFLATE application/rss+xml
  AddOutputFilterByType DEFLATE application/atom+xml
  AddOutputFilterByType DEFLATE image/svg+xml
  AddOutputFilterByType DEFLATE font/woff
  AddOutputFilterByType DEFLATE font/woff2
</IfModule>

Это включает gzip-сжатие для текстовых форматов. На большинстве хостингов работает.

Brotli (более эффективное сжатие) поддерживается через mod_brotli, но он чаще доступен только на VPS. Если на shared только gzip, это нормально, разница 10-20 процентов в размере.

Что НЕ кешировать

Несколько важных исключений.

admin-страницы

Админка WordPress, Битрикса, любой CMS не должна попадать под долгий кеш. Иначе пользователи увидят кешированную версию, и при действиях возникают сбои.

Обычно это решается тем, что админка работает по другому пути (/wp-admin/) и отдаёт другой Cache-Control через PHP-заголовки. Дополнительная настройка в .htaccess не нужна.

Но проверьте, что ваш блок выше не накладывается на админку. В стандартном .htaccess для WordPress правила mod_rewrite для админки идут отдельно, и кеш на них не накладывается.

Корзина магазина и личный кабинет

/cart/, /checkout/, /my-account/ нельзя кешировать. Они должны отдавать private, no-cache.

Если у вас Apache, добавьте отдельное правило:

<IfModule mod_headers.c>
  <FilesMatch "(cart|checkout|my-account)">
    Header set Cache-Control "private, no-cache, must-revalidate"
  </FilesMatch>
</IfModule>

Но это работает не идеально. Лучше, чтобы PHP-движок (WordPress, WooCommerce) сам ставил заголовок при ответе на эти страницы. WooCommerce из коробки делает это правильно.

Динамические JSON-ответы

API-ответы вашего сайта (REST API WordPress, Битрикс REST) не должны попадать под долгий кеш. Раздел в .htaccess для application/json обычно ставит no-cache, но проверяйте.

Конфиг-файл с шестерёнкой и стрелкой к браузеру

Проверка работы кеша

После публикации .htaccess проверяете, что заголовки реально отдаются.

Через curl

curl -sI https://saitfix.ru/style.css

Должны увидеть:

Cache-Control: public, max-age=31536000, immutable
Expires: ...
Content-Type: text/css

Если Cache-Control не виден, конфиг не применился. Проверяйте, что mod_headers и mod_expires включены на хостинге.

Через DevTools

Открываете сайт, F12 > Network. Перезагружаете. Смотрите на CSS и JS в списке. Колонка Status: — 200: первый раз скачивается. — 200 (from cache): из кеша браузера. — 304 Not Modified: проверка по If-None-Match.

После активации кеша при повторной загрузке вы увидите много from cache.

Также в колонке Size рядом со словом disk cache или memory cache будет указано, откуда взято.

Через Yandex Метрика и PageSpeed Insights

PageSpeed Insights в разделе Diagnostics показывает рекомендацию Serve static assets with an efficient cache policy. Если она не активна, значит у вас всё хорошо. Если активна, перечислены файлы, которые кешируются плохо.

Особенности для WordPress

WordPress сам по себе не управляет браузерным кешем для статики. Это делает либо ваш .htaccess, либо плагин кеширования.

Плагины, которые ставят правильные правила: — WP Rocket (платный). — W3 Total Cache (бесплатный, сложный). — WP Super Cache (бесплатный, простой). — Cache Enabler (бесплатный, минималистичный).

При использовании плагина проверяйте: правильные ли он добавляет правила, не дублируются ли с вашими ручными.

Если используете руками, плагин не нужен, или включаете только функцию объединения CSS/JS.

Особенности для Битрикса

Битрикс генерирует свои .htaccess правила для оптимизации. В стандартном файле есть блок mod_expires и mod_headers, но он часто базовый.

Можно дополнить или заменить своим. Главное: соблюдайте порядок правил в .htaccess. Битриксовые блоки идут раньше, ваши ниже.

Особенности для shared-хостинга

На некоторых shared-хостингах модули mod_expires и mod_headers отключены. Признак: правила в .htaccess пишете, но эффекта нет.

Проверка: phpinfo() или ответ хостинга. Если модули выключены, обращайтесь в поддержку с просьбой включить. Большинство российских хостингов идут навстречу.

Если хостинг наотрез отказывает (бывает на самых дешёвых тарифах), часть кеширования можно сделать через <meta http-equiv="cache-control" ...> в HTML, но это работает только для HTML, не для статики.

Как обновлять файлы при кеше

Главная сложность долгого кеша: пользователи видят старые версии CSS/JS до момента, пока кеш не истечёт (год).

Решение: hash в имени файла.

При сборке сайта вы получаете style.abc123.css. При следующей сборке после правки style.def456.css. HTML ссылается на актуальную версию. Старые версии остаются в кеше браузеров, но никто на них не ссылается, и они со временем сами очищаются.

Современные сборщики (Vite, Webpack, Astro):

<link rel="stylesheet" href="/_astro/index.abc123.css">

При каждой сборке хеш меняется, если содержимое изменилось.

Если вы делаете сайт без сборщика, простой способ это query-параметр с версией:

<link rel="stylesheet" href="/style.css?v=20260604">

Меняете дату при каждой правке. Браузер видит новую версию, идёт за ней. Не идеально (не работает с immutable), но рабочее.

Что делать после установки

После публикации .htaccess:

  1. Проверьте через curl, что заголовки приходят.
  2. Откройте сайт в новом окне (incognito), F12 > Network, посмотрите на каждом файле колонку Cache-Control. Должны увидеть max-age=31536000.
  3. Перезагрузите страницу. Большинство файлов должны идти from cache.
  4. Прогоните PageSpeed Insights. Раздел Serve static assets with an efficient cache policy должен исчезнуть из ошибок.

Через 2-4 недели в Яндекс Метрике должна стать заметно лучше скорость для возвращающихся пользователей. У случайных одноразовых эффект минимальный.

Сервер с уровнем кеша и стрелкой в браузер

Чек-лист правильной настройки

  • В .htaccess есть блок mod_expires.
  • В .htaccess есть блок mod_headers с Cache-Control.
  • Картинки, шрифты, CSS, JS получают max-age=31536000, immutable.
  • HTML получает короткий кеш (5-15 минут).
  • API и JSON не кешируются.
  • Корзина и личный кабинет не кешируются.
  • Имена статичных файлов содержат хеш или версию.
  • mod_deflate или mod_brotli включены для сжатия.
  • Проверка через curl показывает правильные заголовки.
  • Проверка через DevTools показывает from cache на повторных загрузках.
  • PageSpeed не выдаёт жалоб на кеш.

Когда стоит делегировать

Постановка кеширующего блока на типичном сайте занимает 1-2 часа. На сайте с большим количеством исключений (магазин с динамическими страницами, личным кабинетом) до 4-6 часов с тестированием.

Эта работа входит в часовую ставку или в любой из тарифов на /#pricing. Если у вас сайт долго грузится при повторных посещениях, или PageSpeed жалуется на отсутствие кеша, опишите ситуацию через /#contact. Связанные материалы по скорости в /blog/category/speed/, там есть отдельные статьи про CDN, шрифты и lazy load.

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

Что даёт браузерный кэш

При повторном заходе браузер не идёт на сервер за картинками, стилями и скриптами, а берёт их с диска. Первая отрисовка ускоряется на сотни миллисекунд, нагрузка на хостинг падает.

Что и на сколько кэшировать

Картинки, шрифты, CSS и JS на год, если в имени файла или в адресе есть версия. Иконку сайта на неделю-другую. HTML на 5-15 минут или без кэша вовсе, он меняется чаще всего.

Что означает immutable

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

Почему правки в стилях не видны

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

Передайте техническую часть в надёжные руки.

Слежу за хостингом, бэкапами и обновлениями. Когда что-то пойдёт не так – звоните мне, не своему программисту, не в спортзал и не маме.

Короткие вопросы по теме

Все вопросы по теме "Скорость сайта"

Заявка

Обсудим задачу

Напишите имя и телефон, выберите удобный канал. Перезвоню или напишу в течение часа в рабочее время.

Куда удобнее ответить?