Кэширование Nginx и Cloudflare: где каждый уровень окупается
Изучите кэширование Nginx и Cloudflare при ограниченном бюджете: что кешировать на краю, в Nginx или в приложении, и где дублирование правил только мешает.

Почему это быстро становится запутанным
Один запрос может пройти через несколько кэшей прежде чем приложение начнёт что‑то делать. Cloudflare может ответить на краю, Nginx может хранить собственную копию, а в приложении могут кэшироваться данные или готовые ответы. Быстрые страницы — это хорошо. Устаревшие — нет. Как только появляется старый контент, команды часто теряют время, пытаясь угадать, какой слой его отдал.
Каждый слой видит запрос по‑своему. Cloudflare заботится об ответе на краю, Nginx — о том, что вернул origin. Приложение обычно кэширует что‑то более специфичное: результат запроса, сгенерённый фрагмент или персонализированный ответ. Если один слой отдаёт старую версию, следующий слой никогда не увидит свежую.
Типичный путь запроса выглядит так:
- Cloudflare проверяет, есть ли у него страница или ресурс.
- Nginx проверяет свой кеш или пересылает запрос дальше.
- Приложение смотрит в память, Redis или базу данных.
Эта стек‑комбинация встречается часто при ограниченном бюджете, потому что каждая часть кажется дешёвой и полезной сама по себе. Проблема начинается, когда команды добавляют кэширование поэтапно без явного плана. Страница кажется медленной — кто‑то добавляет ещё один кэш — и скоро никто не может сказать, какое правило что исправило.
Заголовки часто осложняют ситуацию. Приложение может отправлять один Cache-Control, Nginx — переписывать его, а Cloudflare следовать своим настройкам. Затем вы очищаете один слой и всё ещё видите старую страницу. Через несколько обновлений, приватное окно и проверку заголовков вы уже потратили полчаса на проблему, вызванную пересекающимися правилами.
Дублирование кэширования имеет реальную стоимость. Чем больше слоёв — тем больше очисток, исключений и способов случайно закешировать не то. Для маленького SaaS время на отладку устаревших страниц может стоить дороже, чем чуть более нагруженный origin.
Кэширование работает лучше, когда у каждого слоя одна ясная задача. Как только два слоя пытаются решать одну и ту же задачу, выигрыш в скорости сглаживается, а отладка замедляется.
Что лучше всего делает каждый слой
Каждый уровень кэша решает разный тип задержки. Когда команды смешивают их, они часто кешируют одно и то же три раза и всё равно получают медленные страницы или устаревший контент.
Cloudflare эффективен на краю. Он хорош для файлов, которые многие посетители запрашивают снова и снова: изображения, скрипты, стили и шрифты. Он также может кешировать некоторые полные страницы, когда контент почти не меняется. Так как он ближе к посетителю, он сокращает время передачи и поглощает всплески трафика до того, как они доберутся до вашего сервера.
Nginx лучше работает на origin. Он сидит перед приложением и управляет HTTP‑поведением: заголовки, сжатие, маршрутизация и правила кэширования. Он может кешировать краткоживущие ответы приложения, что полезно для публичных страниц и API‑эндпоинтов, которые многие пользователи запрашивают в одинаковом виде. Он также сообщает Cloudflare, что безопасно кешировать, через понятные заголовки.
Кэш в приложении решает другую задачу. Он хранит работу, которую понимает только приложение: медленный запрос к базе, вычисляемый отчёт, проверку прав или часть дашборда. Это экономит время базы и CPU. Если контент меняется в зависимости от пользователя, аккаунта или плана, приложение обычно узнаёт об этом первым — Cloudflare и Nginx нет.
Полезно думать в терминах расстояния и знаний. Cloudflare далёк от вашего кода, но близок к посетителю. Nginx близок к приложению и хорош в HTTP‑правилах. Приложение знает данные лучше всех.
Такое разделение обычно держит расходы в узде. Пусть Cloudflare обслуживает повторный статический трафик, Nginx кеширует безопасные ответы origin на короткое время, а приложение поддерживает дорогие данные «тёплыми». Когда у каждого слоя своя задача, система быстрее и проще в отладке.
Начните с пути запроса
Хороший план кэширования начинается с простой карты того, что люди запрашивают. Если пропустить этот шаг, вы будете кешировать то, что кажется медленным, а не то, что реально стоит денег.
Запишите основные типы страниц и API‑маршруты. Будьте конкретны: маркетинговые страницы, документация, pricing, скриншоты продукта, HTML дашборда, результаты поиска, login, настройки аккаунта, экспорт, фоновые API‑вызовы.
Простое разделение достаточно:
- публичные страницы, доступные всем
- статические файлы: изображения, JS, CSS
- публичные API‑ответы, используемые многими посетителями
- пользовательские страницы за логином
- приватные API‑маршруты с персональными данными
Затем отметьте, как часто меняется каждый из них. Некоторые материалы обновляются раз в месяц. Некоторые — каждый час. Некоторые значения, как запас товара, метрики в реальном времени или счётчики непрочитанных сообщений, могут меняться каждые несколько секунд. Это определяет, где кэш безопасен, а где он только создаст устаревание.
Сделайте жёсткое разделение между публичным и приватным контентом. Пост в блоге, справочная страница или скриншот продукта обычно могут жить на краю некоторое время. Страница биллинга, админка или всё, что содержит имя пользователя, баланс или индивидуальные права, требует осторожности. Если ответ зависит от cookies, заголовков авторизации или настроек арендатора, считайте его приватным, пока не докажете обратное.
Потом посмотрите, что действительно жрёт CPU. Команды часто ошибаются в догадках. Страница может выглядеть тяжёлой, но дорогостоящая часть может быть в API‑маршруте, который объединяет несколько таблиц, рендерит график или выполняет проверки прав на каждый запрос. Именно там кэширование экономит реальные деньги.
Типичная схема для малого SaaS часто такая: домашняя страница, документация и активы хорошо на краю; Nginx помогает с сжатием, статикой и несколькими краткоживущими публичными ответами; приложение хранит самый контекстозависимый кеш, например дорогие результаты запросов или виджеты дашборда. Такое разделение обычно лучше, чем повторять одни и те же правила в каждом слое.
Если вы можете ответить на четыре вопроса для каждого запроса — кто его видит, как часто он меняется, публичен ли он и сколько стоит его генерация — остальное планирование становится гораздо проще.
Как размещать кэши шаг за шагом
Начните с края, а не изнутри приложения. В большинстве случаев самый дешёвый выигрыш приходит от того, что Cloudflare кеширует статические файлы сперва: CSS, JavaScript, шрифты, изображения и другие версионированные активы. Эти файлы редко требуют обращения к origin, поэтому каждый hit на краю экономит полосу, CPU и время.
Затем посмотрите на нагрузку на origin. Если сервер всё ещё тратит много времени на рендеринг одних и тех же публичных страниц, добавьте короткий Nginx‑кеш только для публичного HTML. Хорошие кандидаты: домашняя страница, pricing, документация или пост в блоге. Держите кеш коротким, обычно 30–120 секунд, чтобы обновления всё ещё быстро показывались.
Простой порядок подходит большинству команд:
- Пусть Cloudflare кеширует статические активы с долгими TTL и версионированными именами файлов.
- Держите страницы входа, ответы авторизации, дашборды и пользовательские API вне edge‑кеша.
- Добавляйте Nginx‑кеш для публичного HTML только если origin всё ещё горячий.
- Кешируйте дорогие чтения из базы в приложении с понятными TTL.
- Измеряйте hit rate, время ответа и нагрузку на сервер после каждого изменения.
Третий шаг — где многие команды ошибаются. Они включают Nginx‑кеш до того, как проверили, не забрал ли уже Cloudflare большую часть простого трафика. Если Cloudflare справляется с активами, вам может не понадобиться много Nginx‑кешей.
Внутри приложения фокусируйтесь на медленных чтениях, которые повторяются. Это может быть таблица цен, feature flags, список планов или тяжёлый отчётный запрос, который многие пользователи запускают. Давайте каждому кешированному результату явный срок жизни: 15 секунд, 1 минута или 5 минут. Подбирайте значение по тому, как часто данные реально меняются.
Простой пример для SaaS проясняет картину. Пусть Cloudflare отдаёт активы лендинга. Пусть Nginx держит публичные маркетинговые страницы 60 секунд при всплесках трафика. Дашборд и всё за логином — вне edge. А внутри приложения кешируйте дорогой запрос к базе, собирающий суммарные данные, на короткое время.
После каждого шага проверяйте изменения. Если hit rate вырос и нагрузка упала — оставьте. Если ничего не поменялось — уберите лишний слой и держите конфигурацию простой.
Простой пример для SaaS
Представьте маленький SaaS для командного планирования. Есть публичная домашняя страница, документация, страница цен, дашборд и API. Самое дешёвое решение часто работает лучше, когда у каждого кэша своя задача.
Публичные маркетинговые страницы можно держать за Cloudflare с долгим кешем. Домашняя страница, посты в блоге, страницы фич и документация обычно не меняются в течение дня, поэтому TTL в несколько часов или даже дольше часто подходит. Cloudflare обслуживает повторные визиты рядом с пользователем, снижает трафик к origin и помогает маленькому серверу пережить запуск или рекламный пик.
Страница цен требует иного правила. Команды меняют планы, тексты пробных периодов и заметки о скидках чаще, чем думают. Эту страницу всё ещё можно кешировать на краю, но с коротким TTL и простыми правилами очистки. Десять минут часто хватает. Если команда меняет цену и хочет увидеть её сразу, очищайте только эту страницу, а не всё подряд.
Для залогиненных пользователей избегайте edge‑кеша. Дашборд, биллинг и API аккаунта должны проходить через Cloudflare без сохранения персонализированных ответов. Внутри приложения кешируйте дорогие данные: лимиты плана, права команды, feature flags и отчёты, которые собираются сотни миллисекунд. Пользователи получают быстрый отклик, а приложение не рискует показать данные одного клиента другому.
Nginx уместен там, где контент публичен, но всё ещё стоит CPU. Частый пример — ресайз изображений. Другой — публичная лента, которую многие запрашивают, хотя она обновляется каждые несколько минут. Nginx может держать такие ответы, чтобы приложение не повторяло одинаковую работу.
Чистая карта маршрутов может выглядеть так:
- Главная, блог и документация: долгий кеш в Cloudflare
- Страница цен: короткий кеш в Cloudflare
- Дашборд и пользовательский API: без edge‑кеша, только кеш в приложении
- Трансформации изображений и публичные фиды: кеш Nginx на origin
Именно так настройка окупается. Если вы кешируете один и тот же полный ответ в Cloudflare, Nginx и приложении, вы обычно получаете ещё один устаревший слой для отладки. Пусть Cloudflare поглощает публичный трафик, Nginx решает повторяющуюся работу origin, а приложение кеширует то, что дорого пересчитывать.
Где дублирование кэша отнимает время
На бумаге дублирование кэширования выглядит безопасно. На практике оно чаще добавляет работы, чем даёт скорость.
Частый пример — публичная страница, кешируемая и Cloudflare, и Nginx. Если страница маленькая, почти статична и уже недорога в отдаче, второй кеш может сэкономить лишь несколько миллисекунд. Зато он однозначно добавляет ещё одно место, где всё может устареть.
Та же проблема внутри приложения. Команды иногда кешируют результаты базы в Redis или памяти, хотя Nginx уже отдал итоговый ответ быстро, и страница почти не меняется. Этот дополнительный кэш усложняет код, правила инвалидации и добавляет ещё одну точку, куда смотреть, когда пользователи жалуются на старый контент.
При ограниченном бюджете каждый кэш должен «платить за аренду». Если один слой уже справляется с задачей, добавление ещё одного ради того же контента — часто просто лишняя работа.
Когда пересечение становится проблемой
Боль обычно начинается с рассинхронизации TTL. Cloudflare может хранить страницу час, Nginx — 10 минут, а кэш в приложении — 24 часа. Кто‑то обновляет цену в полдень, очищает один кэш и думает, что всё в живую. Затем служба поддержки получает три скриншота от трёх пользователей: один видит новую цену, другой — старую страницу из Cloudflare, третий получает свежий HTML с устаревшими данными из кэша приложения. Никто не понимает, какой слой «выиграл», потому что у всех разные сроки жизни.
Именно поэтому дублирование кэша тратит время в первую очередь на отладку, а не только на настройку.
Короткая проверка полезна:
- Если Cloudflare уже хорошо кеширует публичную страницу, спросите, нужен ли Nginx тот же полный ответ.
- Если Nginx отдает ответ за миллисекунды, спросите, нужен ли приложению собственный кеш для того же вывода.
- Если вы не можете объяснить порядок очистки в одном предложении, скорее всего у вас слишком много кэшей.
Обновления усугубляют ситуацию. Одно изменение может означать очистку Cloudflare, удаление файлов Nginx cache, удаление ключей в Redis и иногда прогрев страниц заново. Работа множится, а пользователей интересует лишь корректность страницы.
Проще настроенная система обычно лучше: пусть Cloudflare отвечает за публичное кеширование на краю, Nginx — за обратное проксирование и, возможно, несколько дорогих ответов, а приложение — только за данные, которые действительно дорого пересчитывать.
Ошибки, которые создают устаревший или неверный контент
Самый быстрый способ сломать сайт — закешировать то, что меняется от пользователя к пользователю. Дашборд, корзина, страница аккаунта или страница цен с персональными скидками никогда не должны лежать в публичном кеше только потому, что в одном тесте всё выглядело нормально.
Cookies и заголовки авторизации — обычная ловушка. Если ответ зависит от cookie входа, сессионного токена или заголовка Authorization, считайте его приватным, если у вас нет очень явного правила, которое сначала удаляет личные данные. Одна неправильная запись в Cloudflare или Nginx может показать Алисе страницу, предназначенную для Боба.
Ключи кэша создают более тихие ошибки. Страница может казаться корректной для большинства, но быть неправильной для пользователей на мобильных, на другом языке или с фильтром в URL. Если приложение отдаёт разный вывод по локали, устройству или параметрам запроса, ключ кэша должен включать эти различия.
Типичные промахи выглядят так:
- Английская и французская страницы разделяют один кэш.
- Мобильный и десктопный макеты хранятся в одном ответе.
- Параметры
?page=2или?sort=priceигнорируются. - Тестовый пользователь и платный пользователь попадают на один и тот же HTML.
Долгие TTL усугубляют всё это. Команды часто ставят час или день сначала и обещают починить инвалидацию позже. Порядок неправильный. Тестируйте процесс очистки и прогрева перед увеличением TTL. Начните с короткого срока жизни, подтвердите, что обновления появляются вовремя, и только потом растягивайте TTL там, где правила выдерживают нагрузку.
Ещё одна ошибка — винить всё медленные маршруты в отсутствии кэша. Некоторые маршруты медленны из‑за плохого запроса, чрезмерной работы приложения или нескольких внешних вызовов перед рендером. Кэш может скрыть проблему на время, но не исправит логику. Если инвалидация сложна или контент меняется каждую секунду, вероятно сам маршрут нужно оптимизировать.
Это особенно важно при попытке держать инфраструктуру компактной. Каждый лишний слой усложняет отладку. Когда контент кажется устаревшим, теперь нужно спрашивать, какой слой его держал, какое правило сработало и послал ли приложение неверные заголовки. Публичное кеширование стоит резервировать для контента, который действительно общий, предсказуем и легко обновляем.
Часто задаваемые вопросы
Should I cache the same page in Cloudflare and Nginx?
Обычно нет. Пусть один слой отвечает за свою задачу. Cloudflare подходит для общих статических файлов и некоторых публичных страниц, Nginx — для небольшого набора дорогих публичных ответов, если origin всё ещё перегружен, а приложение должно кешировать то, что понимает только ваш код.
Когда одно и то же полный ответ кешируется в двух или трёх местах, вы получаете больше шагов очистки и больше состояний устаревания без заметного увеличения скорости.
What should Cloudflare cache first?
Начните с версионированных статических активов: CSS, JavaScript, шрифты и изображения. Эти файлы редко меняются, и каждый edge-hit экономит полосу и ресурсы origin.
После этого можно протестировать несколько публичных страниц, которые остаются стабильными, например документацию или блог. Страницы пользователя, авторизация и приватные API держите вне edge-кеша.
When does Nginx cache actually help?
Nginx полезен, когда приложение постоянно рендерит один и тот же публичный ответ. Короткий кеш для публичного HTML, преобразований изображений или публичной ленты может сократить нагрузку на origin.
Если Cloudflare уже убирает большую часть трафика, Nginx может почти не кешировать. Тем не менее он важен для заголовков, сжатия, маршрутизации и обработки запросов.
What belongs in the app cache?
Кладите в приложение то, что дорого и повторяется. Хорошие примеры: тяжёлые SQL-запросы, вычисляемые итоговые значения дашборда, проверки прав, feature flags и отчёты, которые многие пользователи запрашивают снова и снова.
Приложение лучше всего знает, какие данные меняются по пользователю, аккаунту или плану, поэтому это безопасное место для приватного и контекстно-зависимого кеша.
Should logged-in pages ever sit in edge cache?
По умолчанию держите их вне публичного edge-кеша. Если ответ зависит от cookies, сессии или заголовка Authorization, относите его к приватному.
При этом можно кешировать дорогие части внутри приложения — это сократит нагрузку на базу, не рискуя показать данные одного пользователя другому.
How long should I set cache TTLs?
Сначала используйте короткие TTL. Публичная страница в Nginx может начинаться с 30–120 секунд, а статические файлы на edge — жить гораздо дольше при версионировании имён файлов.
Подбирайте TTL по тому, как часто контент действительно меняется. Не переключайтесь сразу на час или день, пока не проверите процесс инвалидации.
Why do I still see old content after a purge?
Чаще всего дело в том, что один из слоёв всё ещё хранит старую версию. Cloudflare, Nginx и приложение могут иметь разные копии с разными TTL.
Проверьте, какой слой ответил на запрос, очистите только его и подтвердите заголовки ответа. Если вы не можете объяснить порядок очистки в одно предложение, значит слоёв слишком много.
How do I know another cache layer is worth it?
Измерьте «горячий» маршрут до и после добавления слоя. Следите за запросами к origin, временем ответа, загрузкой CPU и количеством запросов к базе.
Оставляйте слой только если он реально убирает работу. Если он экономит несколько миллисекунд, но добавляет устаревание и больше шагов очистки — уберите его.
What usually makes cached pages show the wrong content?
Ключи кэша чаще всего ломают корректность. Если вывод меняется по языку, устройству, query string, плану или арендатору, ключ кэша должен учитывать эти различия.
Страница может выглядеть правильно в одном браузере и быть неправильной для мобильных, французских пользователей или для URL с ?page=2 или ?sort=price.
What is a safe starter setup for a small SaaS?
Для небольшой SaaS оставьте минимальную схему: Cloudflare обслуживает статические файлы и стабильный публичный трафик, Nginx отвечает за проксирование и небольшой кеш для дорогих публичных ответов, приложение кеширует тяжёлые запросы к базе с понятными TTL.
Меняйте по одному слою и измеряйте эффект. Такая настройка остаётся быстрой и даёт команде меньше мест для отладки, когда контент устарел.