Главная / База знаний / Кэширование в nginx: fastcgi_cache и proxy_cache
инструкция · 26 октября 2026

Кэширование в nginx: fastcgi_cache и proxy_cache

Разбираем настройку кэширования ответов в nginx перед PHP-FPM (fastcgi_cache) и перед бэкендом (proxy_cache): ключи кэша, обход кэша для авторизованных пользователей, очистка и заголовок X-Cache-Status.

Зачем кэшировать ответы уровнем выше PHP и базы данных

Даже хорошо оптимизированное PHP-приложение с настроенным OPcache и разумной конфигурацией MySQL тратит заметное время на полный цикл обработки каждого запроса: инициализацию фреймворка, выполнение запросов к базе данных, рендеринг шаблона. Для страниц, содержимое которых одинаково для большинства посетителей и меняется не на каждый запрос, а раз в минуты или часы, весь этот цикл можно пропустить полностью, отдав ранее сохранённый готовый ответ прямо на уровне веб-сервера.

Nginx умеет кэшировать полные ответы бэкенда — будь то PHP-FPM через протокол FastCGI (директивы fastcgi_cache_*) или произвольный HTTP-бэкенд, проксируемый через proxy_pass (директивы proxy_cache_*). В обоих случаях используется один и тот же внутренний движок кэширования nginx, работающий с диском или памятью в зависимости от конфигурации, а разница сводится к тому, какой тип соединения используется для получения исходного ответа.

Кэш, расположенный максимально близко к клиенту — на уровне веб-сервера, а не только внутри приложения, — снимает нагрузку сразу со всех нижележащих слоёв: PHP-FPM, базы данных и любых внешних сервисов, к которым обращается приложение при формировании ответа.

Общий принцип многоуровневого кэширования веб-приложений

Эта статья разбирает практическую настройку fastcgi_cache для типичной связки Nginx с PHP-FPM, proxy_cache для случая с обратным прокси перед произвольным бэкендом, объясняет формирование ключа кэша, обход кэша для авторизованных пользователей и POST-запросов, и показывает, как проверить фактическую работу кэша через заголовок X-Cache-Status.

fastcgi_cache_path: где и как хранится кэш

Настройка кэширования начинается с директивы fastcgi_cache_path в контексте http основного конфига nginx — она задаёт путь на диске, структуру каталогов, зону разделяемой памяти для хранения метаданных ключей и лимиты по размеру.

Настройка пути кэширования, зоны разделяемой памяти и лимитов
fastcgi_cache_path /var/cache/nginx/fastcgi levels=1:2 keys_zone=PHPCACHE:10m
    max_size=1g inactive=60m use_temp_path=off;

Параметр levels=1:2 задаёт структуру подкаталогов для хранения файлов кэша (два уровня вложенности по одному и по два символа хеша имени файла) — это защищает файловую систему от накопления десятков тысяч файлов в одном плоском каталоге, что на некоторых файловых системах заметно снижает скорость доступа. Зона keys_zone=PHPCACHE:10m резервирует область разделяемой памяти для хранения метаданных ключей кэша (не самих данных, а информации о них) — 10 мегабайт этой зоны достаточно для хранения метаданных о нескольких сотнях тысяч ключей.

Параметр max_size=1g ограничивает общий объём, который может занять кэш на диске, — при достижении лимита фоновый процесс cache manager внутри nginx удаляет наименее востребованные записи. inactive=60m определяет, через какое время неиспользуемая (ни разу не запрошенная) запись кэша считается устаревшей и удаляется, независимо от значения времени жизни, заданного при создании записи, — это отдельный, независимый механизм от TTL, задаваемого директивой fastcgi_cache_valid ниже.

Формирование ключа кэша и включение кэширования в location

Ключ кэша определяет, какие запросы nginx считает «одним и тем же» ответом — по умолчанию используется схема из протокола, метода и полного URI, но в реальных конфигурациях ключ обычно настраивают явно, чтобы учесть особенности конкретного сайта, например мобильную версию или разные варианты домена.

Явное определение ключа кэша с учётом схемы, метода, хоста и полного URI запроса
fastcgi_cache_key "$scheme$request_method$host$request_uri";

Включение самого кэширования происходит в location, обрабатывающем передачу запроса на PHP-FPM, — директива fastcgi_cache ссылается на имя зоны, заданное в keys_zone, а fastcgi_cache_valid определяет время жизни закэшированного ответа отдельно для каждого кода ответа HTTP.

Включение кэша с разным временем жизни для успешных ответов и ошибок 404
location ~ \.php$ {
    fastcgi_pass unix:/run/php/php8.3-fpm.sock;
    fastcgi_cache PHPCACHE;
    fastcgi_cache_valid 200 10m;
    fastcgi_cache_valid 404 1m;
    include fastcgi_params;
}

Раздельная настройка времени жизни для разных кодов ответа — практически важная деталь: успешные ответы (200) обычно можно кэшировать на заметно больший срок, чем ошибки (404, 500), поскольку временная недоступность конкретного ресурса не должна закэшироваться надолго и мешать доступу к странице сразу после того, как проблема на бэкенде будет устранена.

Обход кэша для авторизованных пользователей и корзины

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

Формирование переменной, определяющей необходимость обхода кэша по нескольким условиям
set $skip_cache 0;
if ($request_method = POST) {
    set $skip_cache 1;
}
if ($cookie_logged_in) {
    set $skip_cache 1;
}
if ($request_uri ~* "/cart/|/checkout/|/account/") {
    set $skip_cache 1;
}

Переменная $skip_cache формируется на основе нескольких независимых условий: метод запроса (POST почти всегда должен обходить кэш), наличие cookie, сигнализирующего об авторизованной сессии (имя cookie зависит от конкретной CMS или фреймворка), и явный список путей, заведомо содержащих персонализированные данные вроде корзины или личного кабинета.

Применение переменной пропуска кэша через связку fastcgi_cache_bypass и fastcgi_no_cache
location ~ \.php$ {
    fastcgi_pass unix:/run/php/php8.3-fpm.sock;
    fastcgi_cache PHPCACHE;
    fastcgi_cache_bypass $skip_cache;
    fastcgi_no_cache $skip_cache;
    fastcgi_cache_valid 200 10m;
    include fastcgi_params;
}

Директивы fastcgi_cache_bypass и fastcgi_no_cache решают на первый взгляд похожую, но разную задачу: fastcgi_cache_bypass определяет, стоит ли брать ответ из уже существующего кэша (1 — не брать, всегда идти на бэкенд), а fastcgi_no_cache — стоит ли сохранять только что полученный от бэкенда ответ в кэш. Указывать оба варианта с одной и той же переменной — стандартная практика: персонализированный запрос не должен ни читать чужой закэшированный ответ, ни записывать свой собственный персонализированный ответ в общий кэш для других посетителей.

proxy_cache: тот же принцип для обратного прокси

Для сценария, где nginx работает как reverse proxy перед приложением на Node.js, Python или другом языке (подробно разобрано в отдельной статье про Nginx как reverse proxy), кэширование настраивается почти идентично, но через директивы с префиксом proxy_ вместо fastcgi_.

Полная настройка proxy_cache для reverse proxy перед приложением на порту 3000
proxy_cache_path /var/cache/nginx/proxy levels=1:2 keys_zone=APPCACHE:10m
    max_size=2g inactive=30m use_temp_path=off;

server {
    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_cache APPCACHE;
        proxy_cache_valid 200 5m;
        proxy_cache_key "$scheme$request_method$host$request_uri";
        add_header X-Cache-Status $upstream_cache_status;
    }
}

Все те же принципы обхода кэша для персонализированных запросов применимы и здесь — через proxy_cache_bypass и proxy_no_cache с теми же условиями по методу запроса, cookie сессии и специфичным путям. Практическая разница между fastcgi_cache и proxy_cache сводится исключительно к типу соединения с бэкендом, тогда как логика формирования ключа, время жизни и обход кэша работают идентично в обоих случаях.

Для приложений с собственным API, отдающим JSON, стоит отдельно продумать, какие именно эндпоинты безопасно кэшировать: справочные данные, не зависящие от конкретного пользователя (список категорий каталога, публичная статистика), кэшируются так же успешно, как обычные HTML-страницы, тогда как персонализированные ответы API (например, список заказов конкретного пользователя) требуют того же обхода кэша, что и HTML-страницы личного кабинета.

X-Cache-Status: проверка фактической работы кэша

Без явного индикатора невозможно понять со стороны клиента, действительно ли конкретный ответ пришёл из кэша nginx или был свежесгенерирован бэкендом, — для диагностики принято добавлять кастомный заголовок ответа на основе встроенной переменной $upstream_cache_status.

Добавление заголовка с состоянием кэша в каждый ответ для диагностики
add_header X-Cache-Status $upstream_cache_status;

Переменная $upstream_cache_status принимает несколько возможных значений: HIT означает, что ответ был отдан из кэша без обращения к бэкенду, MISS — что подходящей записи в кэше не нашлось и запрос ушёл на бэкенд (с последующим сохранением результата в кэш, если это разрешено конфигурацией), BYPASS — что кэш был намеренно пропущен согласно правилам fastcgi_cache_bypass, EXPIRED — что запись в кэше была найдена, но её время жизни истекло, и потребовалось обновление от бэкенда.

Быстрая проверка статуса кэша для конкретной страницы через curl
curl -sI https://example.ru/ | grep -i x-cache-status

Регулярная проверка этого заголовка на ключевых страницах сайта — простой и надёжный способ убедиться, что кэш действительно работает так, как задумано: если ожидаемо кэшируемая страница из раза в раз показывает MISS вместо HIT, это сигнал либо о слишком коротком времени жизни кэша относительно частоты запросов, либо об ошибке в условиях, из-за которой $skip_cache неожиданно равна 1 для этого конкретного запроса.

Инвалидация и очистка кэша

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

Полная очистка кэша FastCGI и перечитывание конфигурации nginx
rm -rf /var/cache/nginx/fastcgi/*
systemctl reload nginx

Для точечной очистки конкретных URL без сброса всего кэша сразу существует стороннее расширение ngx_cache_purge, которое нужно собрать вместе с nginx на этапе компиляции (или использовать сборку, уже включающую этот модуль) — оно добавляет отдельную директиву fastcgi_cache_purge, позволяющую отправить специальный запрос на удаление конкретной закэшированной записи по её ключу.

На практике для многих сайтов проще и надёжнее опираться на разумно короткое время жизни кэша (fastcgi_cache_valid в единицы минут для часто меняющегося содержимого) вместо построения инфраструктуры точечной инвалидации при каждом изменении контента — компромисс между небольшой задержкой в появлении обновлённого контента и заметным упрощением всей системы кэширования.

Устойчивость к сбоям бэкенда: fastcgi_cache_use_stale

Отдельная практическая возможность fastcgi_cache и proxy_cache — продолжать отдавать устаревший, но валидный по структуре ответ из кэша даже в случае, если бэкенд временно недоступен или отвечает с ошибкой, вместо того чтобы показать посетителю страницу с ошибкой.

Отдача устаревшего кэша при сбое бэкенда и фоновое обновление кэша без блокировки текущего запроса
fastcgi_cache_use_stale error timeout updating http_500 http_503;
fastcgi_cache_background_update on;

Директива fastcgi_cache_use_stale со значениями error и timeout заставляет nginx при недоступности бэкенда или превышении таймаута соединения проверить, есть ли для этого запроса устаревшая (просроченная по TTL) запись в кэше, и если есть — отдать именно её вместо ошибки клиенту. Значения http_500 и http_503 расширяют этот список на случаи, когда бэкенд формально ответил, но с кодом серверной ошибки.

fastcgi_cache_background_update дополняет эту схему: при отдаче устаревшего ответа из кэша (пока актуальный ответ ещё не готов) nginx в фоне асинхронно обращается к бэкенду за свежими данными для следующего запроса, не заставляя текущего посетителя ждать полного цикла обновления — сочетание этих двух директив заметно повышает устойчивость сайта к кратковременным проблемам на стороне PHP-FPM или базы данных.

Типичные ошибки при настройке кэширования nginx

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

Слишком долгое время жизни кэша (fastcgi_cache_valid) для часто меняющегося контента — новости, цены, наличие товара на складе — приводит к тому, что посетители видят устаревшую информацию значительно дольше, чем ожидает бизнес-логика сайта.

Отсутствие заголовка X-Cache-Status при отладке — без него невозможно быстро понять, действительно ли кэш работает и почему конкретная страница показывает MISS вместо ожидаемого HIT при повторном обращении.

Игнорирование inactive и max_size в fastcgi_cache_path — без разумных лимитов кэш способен неограниченно расти на диске, особенно на сайтах с большим количеством уникальных URL параметров (например, из-за фильтров каталога), потенциально исчерпав всё доступное дисковое пространство.

Кэширование ответов с кодом ошибки на тот же срок, что и успешных ответов, — если бэкенд временно отдаёт 500 из-за кратковременной проблемы, а fastcgi_cache_valid для этого кода установлен на десятки минут, посетители продолжат видеть ошибку значительно дольше, чем реально длилась сама проблема на бэкенде.

Итог: кэш на уровне веб-сервера как первая линия защиты от нагрузки

Кэширование через fastcgi_cache или proxy_cache — один из самых эффективных по соотношению затрат и результата способов снизить нагрузку на PHP-FPM, базу данных и любые внешние сервисы, к которым обращается приложение, поскольку значительная доля запросов вообще не доходит до этих нижележащих слоёв, если содержимое страницы уже есть в кэше и остаётся актуальным.

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

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

почему мы

Почему стоит выбрать нас

Быстрый запуск

Подберём конфигурацию и развернём проект в день обращения.

Надёжность

NVMe-диски, защита от DDoS и резервные копии по расписанию.

Поддержка 24/7

Дежурные инженеры на связи в любое время суток.

Настройка под ключ

Установим CMS, настроим веб-сервер, SSL и почту за вас.

Перенос без простоя

Аккуратно перенесём сайт и базу данных на новый сервер.

Прозрачные цены

Актуальные тарифы и честный подбор без навязывания.

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

Вопросы и ответы

В чём разница между fastcgi_cache и proxy_cache?

Оба механизма используют один и тот же внутренний движок кэширования nginx, разница только в типе бэкенда: fastcgi_cache применяется при обращении к PHP-FPM по протоколу FastCGI, а proxy_cache — при проксировании HTTP-запросов на любой другой бэкенд (Node.js, Python, другой веб-сервер) через proxy_pass.

Можно ли кэшировать страницы для авторизованных пользователей?

Не рекомендуется без дополнительной логики — по умолчанию стоит полностью исключать из кэша запросы с cookie авторизованной сессии через fastcgi_cache_bypass и fastcgi_no_cache, иначе один пользователь рискует увидеть закэшированную персонализированную страницу другого.

Как узнать, отдаётся ли конкретная страница из кэша nginx?

Через кастомный заголовок ответа, обычно называемый X-Cache-Status, который добавляется директивой add_header на основе переменной $upstream_cache_status и принимает значения HIT (отдано из кэша), MISS (кэш не найден, запрос ушёл на бэкенд) или BYPASS (кэш намеренно пропущен).

Как принудительно сбросить (очистить) кэш nginx для конкретной страницы?

Стандартный nginx с открытым исходным кодом не имеет встроенной команды точечной очистки конкретного URL — обычно используют модуль ngx_cache_purge (собирается отдельно) для точечной очистки, либо просто удаляют файлы кэша с диска, либо снижают fastcgi_cache_valid до значений, при которых устаревание кэша происходит достаточно быстро само по себе.

Нужно ли кэшировать POST-запросы?

Как правило, нет — POST-запросы обычно меняют состояние (отправка формы, оформление заказа) и по своей природе не идемпотентны, поэтому кэш для них по умолчанию не работает в nginx, а попытка обойти это ограничение почти всегда создаёт больше проблем, чем решает.

Что произойдёт, если бэкенд отдаст ошибку 500, пока кэш работает?

Без явной настройки fastcgi_cache_valid для кодов ошибок nginx не закэширует ответ с ошибкой и будет обращаться к бэкенду на каждый следующий запрос, что при аварии бэкенда может дополнительно нагрузить его лавиной повторных запросов, — для этого случая существует директива fastcgi_cache_use_stale.

Сколько места на диске нужно под кэш nginx?

Зависит от количества уникальных URL и размера ответов сайта — директива fastcgi_cache_path задаёт лимит через max_size, при достижении которого nginx автоматически удаляет наименее востребованные записи (по алгоритму, близкому к LRU), не давая кэшу расти неограниченно.

Как оплачивать услуги?

Оплата помесячная, для облачных серверов доступна почасовая тарификация. Принимаются карты, банковские переводы и электронные кошельки.

Есть ли круглосуточная поддержка?

Да, дежурные инженеры на связи 24/7.

Выдаёте ли закрывающие документы?

Да, предоставим необходимые документы для оплаты.

Как оставить заявку?

Заполните форму на странице или нажмите «Заказать» — мы свяжемся и поможем с подбором.

заявка

Оставьте заявку

Ответим и поможем с подбором и настройкой.