MAATRIX / Блог / Кеширование Nginx на сервере: частые ошибки и решения

Кеширование Nginx на сервере: частые ошибки и решения

Кеширование Nginx на сервере: частые ошибки и решения

MAATRIX

Кеш в Nginx настроен, а толку нет: заголовок упорно показывает MISS, где-то наоборот отдаётся вчерашняя версия страницы, а однажды залогиненный пользователь увидел чужой личный кабинет. Кеширование Nginx на сервере ошибается предсказуемо, и почти каждая проблема лечится парой строк конфига. Разберём частые ошибки по схеме «симптом — причина — решение».

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Первый шаг диагностики: заголовок статуса кеша

Прежде чем что-то менять, нужно видеть, что происходит с каждым запросом. Главный инструмент — заголовок статуса кеша, который показывает, была ли отдача из кеша. Добавьте его, если ещё не сделали:

add_header X-Cache-Status $upstream_cache_status;

Теперь у каждого ответа виден статус: HIT — отдано из кеша, MISS — сходили на бэкенд и закешировали, BYPASS — кеш намеренно обошли, EXPIRED — копия устарела и обновлена. Проверяйте его двумя одинаковыми запросами подряд:

curl -sI https://example.com | grep X-Cache-Status
curl -sI https://example.com | grep X-Cache-Status

Если оба раза MISS — кеш не сохраняет ответы, и проблема в этом. Если стабильно HIT, но контент устарел — проблема в сроке жизни или очистке. Если BYPASS там, где ждали HIT, — сработало правило обхода. Статус кеша сразу указывает, в какую сторону копать, поэтому начинайте всегда с него.

Кеш не срабатывает: вечный MISS

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

Первая и самая частая — куки. Если бэкенд отдаёт Set-Cookie в ответе, Nginx по умолчанию считает такой ответ персональным и не кеширует его. А многие приложения ставят сессионную куку вообще всем, даже анонимным гостям. Проверьте, что приходит от бэкенда:

curl -sI http://127.0.0.1:3000 | grep -i set-cookie

Если куки есть на страницах, которые должны кешироваться, нужно либо убрать их на стороне приложения для анонимных запросов, либо явно разрешить кеширование, игнорируя эти куки. Вторая причина — заголовки Cache-Control: no-cache или Cache-Control: private от бэкенда: Nginx их уважает и не кеширует. Третья — метод запроса: по умолчанию кешируются только GET и HEAD. И четвёртая — вы просто забыли директиву proxy_cache в нужном location или объявили зону, но не включили её.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США и РФ. Оплата картой РФ и по СБП.

Арендовать VPS

Отдаётся устаревший контент

Обратная беда: обновили страницу или товар, а посетители видят старую версию. Статус кеша при этом HIT — значит, отдаётся сохранённая копия, срок жизни которой ещё не истёк. Это не поломка, а следствие настройки: вы сказали хранить ответ, скажем, час, и весь час Nginx честно отдаёт его.

Решений два в зависимости от задачи. Если контент меняется предсказуемо, подберите разумный proxy_cache_valid: для новостной ленты минуты, для статичного каталога — десятки минут. Если же обновление должно быть мгновенным, кеш нужно сбрасывать при публикации. В открытой версии Nginx точечная очистка недоступна, поэтому либо чистят весь каталог кеша, либо интегрируют сброс в процесс публикации:

rm -rf /var/cache/nginx/*
systemctl reload nginx

Частая ошибка — поставить очень большой TTL ради нагрузки и забыть про свежесть. Ищите баланс: слишком короткий срок бьёт по бэкенду, слишком длинный показывает устаревшее. Для многих сайтов удачное решение — умеренный TTL плюс сброс кеша при изменении контента.

Куки и параметры ломают попадание в кеш

Тонкая проблема: кеш вроде работает, но HIT случается редко, будто каждый запрос уникален. Обычно виноват ключ кеша, в который попадает что-то изменчивое. Если в proxy_cache_key или в учитываемых параметрах есть метки рекламных кампаний вроде utm_*, то /page?utm_source=a и /page?utm_source=b считаются разными страницами, и кеш дробится на бесполезные копии.

Посмотрите, из чего складывается ключ, и уберите из него шум. Разумный подход — игнорировать маркетинговые параметры при формировании ключа, чтобы все варианты одной страницы попадали в одну ячейку кеша. То же касается кук: если в ключ так или иначе попадает сессионная кука, у каждого посетителя будет свой кеш, и общего HIT не случится никогда. Ключ кеша должен включать только то, что реально влияет на содержимое ответа, — обычно это схема, хост и путь, но не пользовательские метки.

Утечка приватных страниц в общий кеш

Самая опасная ошибка — когда персональная страница попадает в общий кеш и отдаётся чужим людям. Пользователь заходит в личный кабинет, эта страница кешируется, и следующий анонимный посетитель видит его данные. Причина всегда одна: не настроен обход кеша для приватных запросов.

Обязательный минимум — исключить из кеша авторизованных пользователей и чувствительные пути двумя директивами вместе:

set $skip_cache 0;
if ($http_cookie ~* "session|logged_in") { set $skip_cache 1; }
if ($request_uri ~* "/(account|cart|checkout)") { set $skip_cache 1; }
proxy_cache_bypass $skip_cache;
proxy_no_cache $skip_cache;

Ключевой момент — оба параметра. proxy_cache_bypass не отдаёт из кеша, а proxy_no_cache не записывает ответ в кеш. Если оставить только первый, вы обойдёте кеш при чтении, но всё равно сохраните персональную страницу — и она утечёт следующему. После настройки обязательно проверьте: залогиньтесь и убедитесь, что ваши приватные страницы отдаются со статусом BYPASS, а не HIT.

Кеш переполняет диск и другие эксплуатационные грабли

Реже, но встречается: сервер внезапно упирается в нехватку места, и виноват разросшийся кеш. Это происходит, когда в зоне не задан или задан слишком большим max_size, и кеш растёт, пока не займёт весь диск. Проверьте его объём и настройки:

du -sh /var/cache/nginx

В директиве proxy_cache_path обязательно указывайте max_size с запасом до предела диска и inactive, чтобы редко запрашиваемые объекты удалялись. Ещё одна эксплуатационная тонкость — производительность диска: кеш активно читается и пишется, и на медленном HDD выигрыш меньше ожидаемого, а под нагрузкой диск становится узким местом. Для кеширующего сервера предпочтителен NVMe.

Наконец, помните, что кеш лечит симптом высокой нагрузки, но не безграничен. Если даже с кешем бэкенд захлёбывается на уникальных запросах, а диск не успевает, значит, проекту нужен более мощный сервер. Кеширование выжимает максимум из имеющегося железа, но когда потолок достигнут, честнее взять VPS с быстрым NVMe и запасом ресурсов — у MAATRIX это доступно в локациях RU, US и UK с оплатой из России картой или криптой.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США и РФ. Оплата картой РФ и по СБП.

Арендовать VPS

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

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

Почему кеш Nginx всегда показывает MISS?

Чаще всего бэкенд отдаёт Set-Cookie или Cache-Control: no-cache, из-за чего Nginx считает ответ персональным; проверьте заголовки ответа бэкенда.

Как перестать отдавать устаревшие страницы?

Подберите адекватный proxy_cache_valid под частоту обновлений или сбрасывайте кеш при публикации нового контента.

Из-за чего HIT почти не случается?

В ключ кеша попадает изменчивое — сессионные куки или utm-метки; уберите шум, оставив в ключе только схему, хост и путь.

Как не допустить утечки приватных страниц в кеш?

Настройте обход кеша для авторизованных и чувствительных путей сразу двумя директивами: proxy_cache_bypass и proxy_no_cache.

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.