// Engineering Log
HTTPS и веб-сервер на практике: Часть 4 — Кеширование HTTP и CDN: Cache-Control, ETag, proxy_cache и сброс кеша
Опубликовано 06.11.2026 · Автор: Михаил Горбачёв
// Быстрый маршрут
Эта статья относится к теме Серверы и инфраструктура.
Кеширование — самый дешёвый способ ускорить сайт и снизить нагрузку на сервер: ответ, который не нужно заново генерировать и передавать, приходит мгновенно. Но у кеша есть обратная сторона — пользователи видят старые стили после выкладки, CDN раздаёт одному посетителю личную страницу другого, а изменения на сайте «не применяются». Почти все такие проблемы решаются правильными заголовками Cache-Control и пониманием того, где именно хранится копия. Краткий обзор заголовков кеширования — в статье «Заголовки HTTP», здесь — как ими пользоваться.
Где хранятся копии
Между пользователем и приложением обычно несколько кешей:
- Кеш браузера — личный, только для одного пользователя.
- CDN (Cloudflare, облачные и российские CDN) — общий кеш на серверах по всему миру; одна копия раздаётся всем посетителям.
- Обратный прокси — Nginx с
proxy_cache, Varnish — общий кеш рядом с приложением. - Кеш внутри приложения — Redis, memcached, кеш страниц в CMS. К HTTP-заголовкам отношения не имеет.
Правила для первых трёх задаёт сервер в заголовках ответа. Общие кеши (CDN, прокси) по умолчанию осторожнее браузера, и у CDN есть собственные настройки, которые могут переопределять заголовки.
Как кеш решает, что делать
Копия в кеше бывает свежей или устаревшей. Свежую кеш отдаёт, не спрашивая сервер. Устаревшую сначала проверяет — условным запросом с If-None-Match (по ETag) или If-Modified-Since (по Last-Modified). Если ресурс не изменился, сервер отвечает коротким 304 Not Modified без тела, и кеш продлевает копию.
Сколько копия остаётся свежей, задаёт Cache-Control: max-age в секундах. Если ни Cache-Control, ни Expires нет, кеши вправе сами оценить срок — обычно 10 % от времени с момента Last-Modified. Файл, изменённый год назад, браузер может считать свежим больше месяца. Поэтому явные заголовки нужны всегда.
Директивы Cache-Control
| Директива | Смысл |
|---|---|
max-age=N | свежая N секунд |
s-maxage=N | то же, но только для общих кешей; приоритетнее max-age |
no-cache | хранить можно, но перед каждым использованием проверять у сервера |
no-store | не хранить нигде |
private | только браузер, общим кешам нельзя |
public | можно хранить в общих кешах, даже если запрос был с Authorization |
must-revalidate | устаревшую копию нельзя отдавать без проверки, даже если сервер недоступен |
immutable | ресурс не изменится — не проверять даже при обновлении страницы |
stale-while-revalidate=N | N секунд после устаревания отдавать старую копию, обновляя её в фоне |
stale-if-error=N | N секунд отдавать старую копию, если сервер отвечает ошибкой |
Для CDN есть отдельный заголовок CDN-Cache-Control (RFC 9213): он действует только на CDN и не виден браузеру. Так можно держать страницу в CDN час, а в браузере — не кешировать.
Готовые стратегии
Статика с хешем в имени (app.3f9a1c.js, style.8b2e.css — так собирают Vite, webpack, Hugo Pipes): при изменении файла меняется имя, поэтому старую копию можно хранить вечно.
Cache-Control: public, max-age=31536000, immutableHTML-страницы: ссылки на новые версии статики лежат в HTML, поэтому HTML должен обновляться сразу.
Cache-Control: no-cache
ETag: "5f2a-18c4"Браузер хранит страницу, но каждый раз проверяет: если ничего не изменилось — 304 без тела.
Статика без хеша (картинки из CMS, favicon.ico, robots.txt): короткий срок и проверка.
Cache-Control: public, max-age=3600, stale-while-revalidate=86400Личные страницы и ответы API с данными пользователя:
Cache-Control: private, no-storeПубличные данные API, которые меняются часто (курсы, остатки):
Cache-Control: public, max-age=10, stale-while-revalidate=30Настройка в Nginx
Заголовки для статики и HTML:
location ~* \.(?:js|css|woff2)$ {
# только для файлов с хешем в имени
add_header Cache-Control "public, max-age=31536000, immutable" always;
}
location ~* \.(?:png|jpe?g|webp|avif|svg|ico)$ {
add_header Cache-Control "public, max-age=86400" always;
}
location / {
add_header Cache-Control "no-cache" always;
try_files $uri $uri/ /index.html;
}Nginx сам отдаёт ETag и Last-Modified для статических файлов и отвечает 304 на условные запросы. Для ответов приложения ETag должно ставить приложение.
Кеш в Nginx: proxy_cache
Nginx может сам хранить ответы приложения и отдавать их без обращения к нему:
proxy_cache_path /var/cache/nginx/app levels=1:2 keys_zone=app:50m
max_size=2g inactive=7d use_temp_path=off;
server {
location / {
proxy_pass http://127.0.0.1:8080;
proxy_cache app;
proxy_cache_key "$scheme$host$request_uri";
proxy_cache_valid 200 301 10m;
proxy_cache_valid 404 1m;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_cache_background_update on;
proxy_cache_lock on;
# не кешировать для вошедших пользователей
proxy_cache_bypass $cookie_sessionid;
proxy_no_cache $cookie_sessionid;
add_header X-Cache-Status $upstream_cache_status always;
}
}proxy_cache_use_stale— при ошибке приложения отдавать устаревшую копию: сайт остаётся доступным, пока приложение перезапускается;proxy_cache_background_updateиupdating— обновлять устаревшую копию в фоне, отдавая старую (аналогstale-while-revalidate);proxy_cache_lock— при промахе к приложению идёт один запрос, остальные ждут его результата. Защищает от лавины запросов, когда популярная страница выпала из кеша;X-Cache-StatusпокажетHIT,MISS,EXPIRED,STALE,UPDATINGилиBYPASS.
Nginx уважает заголовки приложения: не кеширует ответы с Set-Cookie, с Cache-Control: private, no-store, no-cache, а срок из Cache-Control: max-age ставит выше, чем proxy_cache_valid.
Микрокеширование — кеш на одну секунду (proxy_cache_valid 200 1s) для публичных страниц под нагрузкой: при тысяче запросов в секунду к приложению уходит один, а данные устаревают не больше чем на секунду.
CDN
Что важно знать о CDN:
- CDN кеширует по своим правилам. Cloudflare по умолчанию кеширует только статику по расширению файла (
.js,.css, картинки, шрифты), но не HTML. Чтобы кешировать страницы, нужно правило кеширования (Cache Rules). Другие CDN могут, наоборот, кешировать всё, что разрешено заголовками; - ключ кеша — обычно хост, путь и строка запроса. Параметры
utm_source,fbclid,yclidсоздают тысячи копий одной страницы — в настройках CDN их стоит исключать из ключа; - cookie. Если ответ зависит от cookie, а CDN кеширует его по адресу, один посетитель получит страницу другого. Персональные ответы — только
privateили обход кеша по наличию cookie сессии; - статус кеша виден в заголовках: у Cloudflare —
CF-Cache-Status(HIT,MISS,EXPIRED,DYNAMIC— не кешируется по правилам,BYPASS— обход по заголовкам ответа), у других —X-Cache, а заголовокAgeпоказывает возраст копии.
Проверка:
curl -sI https://example.ru/assets/app.3f9a1c.js | grep -iE 'cache-control|cf-cache-status|x-cache|age|etag'Повторите запрос: при правильной настройке во второй раз будет HIT и ненулевой Age.
Сброс кеша
- Имена файлов с хешем — основной способ для статики: сбрасывать ничего не нужно, новая версия — новый адрес.
- Параметр версии (
style.css?v=42) — работает, если CDN учитывает строку запроса в ключе; хуже хеша, потому что версию меняют вручную. - Purge в CDN — через панель или API, по адресам или целиком. После выкладки полезно сбрасывать HTML; сброс «всего» после каждой выкладки лишает смысла кеш статики.
- Nginx proxy_cache — удалить каталог кеша или отдельные файлы; в бесплатной версии Nginx нет команды сброса по адресу, её дают сторонние модули или Nginx Plus.
- Кеш браузера сбросить с сервера нельзя. Если вы отдали файл с
max-age=31536000без хеша в имени, пользователи будут видеть старую версию до истечения срока или очистки кеша. Заголовок ответаClear-Site-Data: "cache"очищает кеш сайта в браузере, но только когда браузер получит ответ с ним — а страницу, которая сама лежит в кеше, браузер у сервера не запрашивает. Поэтому длинный срок — только для файлов с хешем.
Типичные ошибки
- Нет
Cache-Controlвообще — браузеры кешируют по эвристике, и после выкладки часть пользователей видит старую вёрстку. max-ageна год дляstyle.cssбез хеша в имени — изменения не доходят до вернувшихся посетителей.- HTML кешируется надолго — страница ссылается на удалённые при выкладке файлы старой сборки, сайт «ломается» у части пользователей.
- Персональная страница без
privateза CDN с кешированием HTML — утечка данных между пользователями. no-cacheвместоno-storeтам, где данные не должны сохраняться на диске вовсе.- Сброс всего кеша CDN при каждой выкладке — после неё все запросы идут на сервер одновременно.
- Отладка «почему не обновилось» с включённым кешем браузера — проверяйте curl’ом или с Disable cache в DevTools.
// Похожая задача
Если у вас похожая ситуация
Эта статья относится к одной из рабочих тем. Можно продолжить чтение по теме, перейти на главную, чтобы понять, чем я занимаюсь, или сразу открыть услуги.
Тема статьи
Серверы и инфраструктура
VPS, Linux, веб-стек, миграции, хостинг, базы данных и базовая эксплуатация.
Часто с этим приходят
- Перенести сайт или сервис на новый сервер
- Настроить Linux, Nginx, базу данных и бэкапы
- Разобраться, почему всё работает нестабильно
// Следующий шаг
Если вам нужна не только статья, а помощь по этой теме, удобнее сразу перейти в услугу. Главная и подборка материалов остаются рядом.
Открыть услуги// Reviews
Отзывы по теме
Спасибо Михаилу за отзывчивость. Созвонились, объяснил как сделать самому. Обращаюсь уже второй раз, все супер и оперативно.
Спасибо Михаилу за отзывчивость. Созвонились, объяснил как сделать самому. Обращаюсь уже второй раз, все супер и оперативно.
Хочу выразить огромную благодарность специалисту, который настроил мне ЧПУ на OpenCart. Настроить ЧПУ оказалось легко и просто, и я рад, что наконец нашел профессионала, который сделал всё качественно и без лишних сложностей. До этого я сменил четырёх специалистов, и каждый раз возникали проблемы с настройкой, но этот человек справился с задачей идеально.
Хочу выразить огромную благодарность специалисту, который настроил мне ЧПУ на OpenCart. Настроить ЧПУ оказалось легко и просто, и я рад, что наконец нашел профессионала, который сделал всё качественно и без лишних …
Отличная работа, обращаюсь не первый раз, находит решения к сложным задачам. Рекомендую.
Отличная работа, обращаюсь не первый раз, находит решения к сложным задачам. Рекомендую.
Отличная работа! Выполнил поставленную задачу в срок и без ошибок. Было приятно сотрудничать, рекомендую.
Отличная работа! Выполнил поставленную задачу в срок и без ошибок. Было приятно сотрудничать, рекомендую.
Отличный специалист, вник в проблему, разобрался, исправил. Рекомендую.
Отличный специалист, вник в проблему, разобрался, исправил. Рекомендую.
Нужно было решить проблему с SSL сертификатом на сервере, который был выпущен через Ngnix Proxy manager. Михаил уточнил все детали, как у меня все устроено, попросил доступы чтобы оценить реальность решения задачи, т. к. до этого не сталкивался с подобным сервисом. Быстро разобрался и решил мою проблему. Идеальное сотрудничество)
Нужно было решить проблему с SSL сертификатом на сервере, который был выпущен через Ngnix Proxy manager. Михаил уточнил все детали, как у меня все устроено, попросил доступы чтобы оценить реальность решения задачи, т. …
Диагностика Nginx Proxy Manager в docker контейнере и решение проблемы
15.03.2024 · ★ 5/5
// Contact
Нужна помощь?
Свяжись со мной и я помогу решить проблему
Написать в TelegramОтвечаю в течение рабочего дня (03:00–13:00 GMT)
Или оставьте заявку здесь:
// Related