Как настроить кэш браузера на сайте
Кэш браузера хранит копии картинок, CSS, JavaScript и шрифтов. Сервер задает правила через заголовки ответа, поэтому посетитель повторно использует статические файлы без новой загрузки. Статья предназначена владельцам и разработчикам сайтов, а не пользователям, которым нужно очистить кэш. Вы настроите Apache или nginx, проверите результат и организуете обновление файлов через новые имена.
- Что такое кэш браузера и зачем его настраивать
- Заголовки кэширования: Cache-Control, Expires, ETag, Last-Modified
- Как включить кэширование в .htaccess через mod_expires
- Cache-Control через mod_headers
- Как настроить кэширование в nginx
- Какой срок кэширования ставить для разных файлов
- Как проверить, что кэширование работает
- Как обновить файл, который уже закэширован у посетителей
- Ошибки при настройке кэширования на сервере
Что такое кэш браузера и зачем его настраивать
Браузер получает файл вместе с правилами его хранения. Он сравнивает срок свежести ресурса с текущим временем и решает, использовать копию или обратиться к серверу.

При повторном открытии страницы браузер берет свежую картинку или таблицу стилей из локального кэша. Серверу не приходится передавать эти данные снова, поэтому сокращаются сетевые запросы и объем трафика.
После окончания срока свежести браузер может отправить условный запрос. Если файл не изменился, сервер вернет ответ 304 без тела ресурса. При изменении файла сервер передаст новую копию.
Кэширование ускоряет повторные посещения и переходы между страницами.
Повторное использование ресурсов может улучшить показатели Core Web Vitals, включая скорость отображения крупного элемента страницы. Результат зависит от того, какие ресурсы браузер уже сохранил. При первом посещении локальный кэш еще не помогает загрузить эти файлы.
Заголовки кэширования: Cache-Control, Expires, ETag, Last-Modified
Правила кэширования передает сервер в заголовках ответа. Браузер отправляет собственные заголовки запроса, но они не заменяют политику сервера.
| Заголовок | Что делает | Пример значения |
|---|---|---|
| Cache-Control | Задает срок свежести и условия хранения ответа | public, max-age=2592000 |
| Expires | Указывает момент окончания свежести | HTTP-дата в GMT |
| ETag | Передает идентификатор версии ресурса | "asset-a81c" |
| Last-Modified | Передает дату последнего изменения | HTTP-дата в GMT |
Если ответ содержит Cache-Control: max-age и Expires, браузер определяет срок свежести по max-age.
Значения двух заголовков согласуйте между собой. Заголовки ETag и Last-Modified решают другую задачу: помогают проверить, изменился ли сохраненный ресурс.
Директивы Cache-Control
Директивы разделяйте запятыми. Для версионированного общего файла подойдет сочетание public, max-age=31536000, immutable.
| Директива | Поведение | Когда применять |
|---|---|---|
max-age | Задает свежесть в секундах | 2592000 – 30 дней; 31536000 – год |
public | Разрешает хранение в общих кэшах | Публичные картинки, CSS и JavaScript |
private | Оставляет хранение только в личном кэше | Персональный ответ без чувствительных данных |
no-cache | Разрешает хранение, но требует перепроверки перед использованием | Публичный HTML, который часто меняется |
no-store | Запрещает сохранение ответа | Чувствительные персональные данные |
must-revalidate | Запрещает использовать устаревшую копию без успешной проверки | Ответы, где старая версия недопустима |
immutable | Показывает, что ресурс не меняется в срок свежести | Файл с хешем в имени |
s-maxage | Задает срок свежести для общих кэшей | Отдельная политика CDN |
no-cache не запрещает хранение файла. Для запрета сохранения используйте no-store.
Директива s-maxage действует для общих кэшей, а браузер ориентируется на max-age.
Документация MDN о Cache-Control подробно описывает эти директивы.
Как ETag и Last-Modified приводят к ответу 304
Браузер возвращает ETag в заголовке If-None-Match. Для даты изменения он использует If-Modified-Since.
Сервер сравнивает полученный валидатор с текущим ресурсом. Если условие подтверждает отсутствие изменений, сервер отправляет 304 без тела. Браузер использует сохраненный файл.
Сетевой запрос при этом все равно происходит.
Как включить кэширование в .htaccess через mod_expires
Файл .htaccess работает на Apache, если хостинг разрешает такие директивы. Nginx этот файл не читает, поэтому сначала определите сервер, который отдает статику.
Перед правкой скачайте резервную копию .htaccess. Ошибка синтаксиса может вызвать ответ 500 и отключить страницы сайта.
- Откройте корневой каталог сайта через файловый менеджер хостинга или SFTP. Включите показ скрытых файлов, если
.htaccessне виден. - Попросите хостинг подтвердить работу
mod_expiresи разрешение директив в.htaccess. При доступе к серверу выполнитеapachectl -Mи найдитеexpires_module. - Добавьте блок в существующий файл, сохранив правила CMS. Если файла нет, создайте его в корне сайта.
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/jpeg "access plus 30 days"
ExpiresByType image/png "access plus 30 days"
ExpiresByType image/gif "access plus 30 days"
ExpiresByType image/webp "access plus 30 days"
ExpiresByType image/avif "access plus 30 days"
ExpiresByType image/svg+xml "access plus 30 days"
ExpiresByType image/x-icon "access plus 30 days"
ExpiresByType text/css "access plus 30 days"
ExpiresByType text/javascript "access plus 30 days"
ExpiresByType application/javascript "access plus 30 days"
ExpiresByType font/woff2 "access plus 30 days"
ExpiresByType application/pdf "access plus 30 days"
ExpiresByType text/html "access plus 0 seconds"
</IfModule>ExpiresActive On включает правила модуля. Каждая строка ExpiresByType сопоставляет срок с MIME-типом ответа.
Для JavaScript предпочтителен text/javascript. Правило для application/javascript охватывает файлы, которые сервер отдает с этим типом.
Блок задает 30 дней, то есть max-age=2592000, для статики.
HTML получает нулевой срок свежести и не хранится месяц без перепроверки. Нулевой срок не запрещает сохранение ответа.
Откройте отдельный CSS-файл после сохранения настроек. В ответе должен появиться Cache-Control с соответствующим сроком и заголовок Expires. Если сервер вернул 500, восстановите резервную копию и изучите журнал ошибок Apache.
Cache-Control через mod_headers
Модуль mod_headers задает политику напрямую. Используйте его вместо конкурирующего правила mod_expires для той же группы файлов.
Применяйте годовой срок только к статике, которая получает новое имя после изменения.
<IfModule mod_headers.c>
<FilesMatch "\.(css|js|jpe?g|png|gif|webp|avif|svg|ico|woff2)$">
Header set Cache-Control "max-age=31536000, public, immutable"
</FilesMatch>
</IfModule><IfModule mod_headers.c>включает правила при загруженном модуле.<FilesMatch ...>выбирает CSS, JavaScript, изображения, значки и шрифт WOFF2. Последовательность\.означает буквальную точку.Header set Cache-Control ...задает годовой срок, общий кэш и неизменяемость ресурса.</FilesMatch>закрывает выбор файлов.</IfModule>закрывает условие модуля.
Для статики без версии поставьте max-age=86400, public, то есть сутки.
Попросите хостинг включить mod_headers и разрешить директивы категории FileInfo. При доступе к серверу найдите headers_module в выводе apachectl -M. Ответ выбранного файла покажет, сработало ли правило.
Публичному HTML задайте отдельную политику:
<IfModule mod_headers.c>
<FilesMatch "\.html?$">
Header set Cache-Control "no-cache"
</FilesMatch>
</IfModule>Правило охватывает файлы .htm и .html. CMS часто формирует страницы без расширения, поэтому для таких маршрутов задайте заголовок в приложении.
Как настроить кэширование в nginx
Правила nginx размещают внутри блока server нужного виртуального хоста. Пример рассчитан на каталог /assets/ с файлами, в именах которых есть версия или хеш.
- Подключитесь к серверу по SSH и выполните
sudo nginx -T. Вывод покажет действующую конфигурацию и подключенные файлы. - Откройте файл с нужным блоком
serverи сохраните его копию перед изменением. - Добавьте правило внутри
server. Если подходящийlocationуже есть, измените его вместо создания конкурирующего блока.
location ~* ^/assets/.*\.(css|js|jpe?g|png|gif|webp|avif|svg|ico|woff2)$ {
try_files $uri =404;
expires off;
add_header Cache-Control "max-age=31536000, public, immutable";
}expires off отключает формирование заголовков модулем expires в этом блоке. Полное значение Cache-Control задает одна директива add_header.
Для файлов без версии замените значение на max-age=86400, public.
Если вам достаточно срока свежести без public и immutable, замените обе строки expires и add_header одной:
expires 365d;Этот вариант задает Expires и Cache-Control с max-age=31536000, то есть на 365 дней.
Добавление add_header внутри location может изменить наследование заголовков родительского блока. Сохраните нужные заголовки безопасности в эффективной конфигурации этого location.
Проверьте конфигурацию командой sudo nginx -t. При успешной проверке выполните sudo nginx -s reload. Запрос к существующему файлу из /assets/ должен вернуть годовой срок и нужные заголовки.
Если проверка конфигурации завершилась ошибкой, не перезагружайте nginx.
Для отката восстановите копию файла, повторите sudo nginx -t и выполните sudo nginx -s reload после успешной проверки.
Какой срок кэширования ставить для разных файлов
Срок выбирайте по способу обновления ресурса. Расширение файла само по себе не показывает, как часто меняется содержимое.
| Тип файла | Рекомендуемый срок | Cache-Control |
|---|---|---|
| Статика с хешем или версией | Год, 365 дней | public, max-age=31536000, immutable |
| Статика без версии | Сутки, если задержка допустима | public, max-age=86400 |
| Общедоступный PDF | 30 дней, если задержка допустима | public, max-age=2592000 |
| Публичный HTML | Перепроверка перед использованием | no-cache |
| Личная страница без чувствительных данных | Хранение только в браузере с перепроверкой | private, no-cache |
| Личный кабинет | Без сохранения ответа | no-store |
HTML с no-cache может храниться, но браузер запросит проверку перед повторным использованием. Личные ответы с чувствительными данными отправляйте с no-store, чтобы кэш не сохранил их.
Если файл без версии должен обновляться сразу, используйте no-cache вместо суточного срока.
Как проверить, что кэширование работает
Проверяйте заголовки сервера и повторное использование файла браузером. Один из этих признаков без другого не дает полной картины.
Проверка в DevTools
- Откройте сайт в Chrome и запустите инструменты разработчика клавишей F12.
- Перейдите на вкладку Network и временно включите «Disable cache». Перезагрузите страницу.
- Выберите запрос CSS, картинки или JavaScript. В разделе «Response Headers» найдите
Cache-Control,Expires,Content-Type,ETagиLast-Modified. - Снимите «Disable cache» и откройте другую страницу с тем же ресурсом. Сравните объем переданных по сети данных: локальная копия не требует повторной передачи тела файла.
Ответ 304 означает сетевую перепроверку без повторной передачи тела.
Для свежего ресурса браузеру обычно не нужна даже перепроверка. Не включайте принудительную перезагрузку при оценке обычного поведения посетителя: такой режим может обойти кэш.
Проверка заголовков через curl
В терминале выполните команду для существующего файла, подставив адрес своего сайта:
curl -I https://example.com/assets/main.3f9a1c.cssКлюч -I запрашивает заголовки методом HEAD. Для перенаправления добавьте -L и изучите конечный ответ.
Если сервер обрабатывает HEAD иначе, получите заголовки обычного GET-ответа:
curl -sS -D - -o /dev/null https://example.com/assets/main.3f9a1c.cssВторая команда рассчитана на оболочку с устройством /dev/null, например Linux или macOS. Она выводит заголовки и отбрасывает тело ответа.
Для годовой политики вы увидите Cache-Control: max-age=31536000, public, immutable.
Curl не хранит постоянный кэш браузера, поэтому повторный запуск сам по себе не обязан дать 304. Ответ 200 с ожидаемой политикой хранения подходит для этой проверки.
Проверка в PageSpeed Insights
Запустите аудит публичной страницы в PageSpeed Insights и откройте замечания о сроках хранения статических ресурсов. Сравните перечисленные адреса с заголовками из Network.
Аудит показывает проблему на публичном адресе, но не меняет настройки сервера. Исправляйте те файлы, которые отдает ваш Apache, nginx или CDN.
Как обновить файл, который уже закэширован у посетителей
Измените URL ресурса при публикации новой версии. Браузер воспримет новый адрес как новый файл и не возьмет старую копию.
- Опубликуйте измененный файл под новым именем, например
main.3f9a1c.css. Его адрес должен вернуть 200 и правильныйContent-Type. - Замените ссылку на файл в шаблоне: для CSS измените
href, для JavaScript –src. - Откройте страницу и найдите новый адрес в Network. В запросе появится новая версия ресурса.
<link rel="stylesheet" href="/assets/main.3f9a1c.css">
<script src="/assets/main.7bd42e.js" defer></script>Сборщик проекта может вычислять хеш и обновлять ссылки автоматически. CMS тоже может добавлять версию к имени или URL. Включите этот шаг в процесс публикации, чтобы не менять файлы вручную.
Параметр main.css?v=2 тоже меняет URL.
CDN может исключать параметры из ключа кэша, поэтому хеш в имени обычно предсказуемее для сложной инфраструктуры. При каждом изменении содержимого публикуйте новое имя файла.
Не меняйте версию при каждом открытии страницы. Такой подход отключит повторное использование кэша.
Сохраните предыдущие файлы на сервере на время перехода. Уже открытая страница может продолжать запрашивать старые ресурсы. Для отката верните ссылки на предыдущую версию в шаблоне.
Ошибки при настройке кэширования на сервере
- После правки .htaccess появился ответ 500. Восстановите копию и проверьте синтаксис, разрешенные директивы и журнал Apache. Директива отсутствующего модуля вне обертки
IfModuleтоже может вызвать ошибку. - Правило внутри IfModule ничего не меняет. Проверьте наличие нужного модуля и разрешения хостинга. Если модуль выключен, Apache пропускает содержимое обертки.
- HTML хранится месяц. Удалите длинный
max-ageи назначьтеno-cache. Браузеры с уже сохраненным свежим ответом получат новую политику только после следующего обращения к серверу. - Личная страница получает public. Отделите персональные маршруты и задайте
privateилиno-store. - Файл без версии хранится год. Опубликуйте измененный файл под новым именем и сократите срок для остальных неверсионированных ресурсов.
- Заголовки не совпадают с настройками. Статику может отдавать другой уровень: nginx, CDN, приложение или хостинг. Измените политику на том уровне, который формирует конечный ответ.
- В ответе несколько max-age. Уберите конкурирующие правила
mod_expires,mod_headersи приложения. - После добавления location исчезли заголовки. Проверьте наследование
add_headerи верните нужные заголовки в эффективный блок.
Совет от нашей редакции: сначала настройте версионирование CSS и JavaScript, затем увеличивайте срок их хранения до года. Так обновления не застрянут у посетителей в старом кэше.
Популярное за неделю
- Как создать сайт самому в 2026: 4 способа + пошаговая инструкция 34 мин чтения
- Лучшие конструкторы для создания сайтов — плюсы, минусы и сравнения 22 мин чтения
- Как пользоваться режимом эмуляции мобильных устройств в Chrome 11 мин чтения
- Подбираем бесплатный компилятор для C / C++ 12 мин чтения
- 12 инструментов для поиска уязвимостей на сайте 4 мин чтения
- 15 инструментов для тестирования скорости сайта 11 мин чтения
Комментарии
Добрый день скажите пожалуйста как сделать кеш для этого https://mc.yandex.ru/metrika/advert.gif (60 минут) а так первый вариант идеально работает а вот с этим чет не работает первый и второй, может что-то не так делаю?
Расписано отлично, но ничего не работает. Гугл Page speed как спрашивал это сделать, так и спрашивает.
Спасибо работает, если принимаете заявки то напишите статью
Спасибо, брат! Помог!
Кодировка пишет не подходит(<ifModule mod_expires.c>)
У меня ANSI_X3.4-1968