Varnish Cache в 2026 остаётся одним из самых эффективных способов снизить TTFB и разгрузить PHP-FPM и базу данных на контентных WordPress-сайтах и на API с большим числом повторяющихся GET-запросов. CDN хорошо закрывает статику и часть HTML, но Varnish ценен как управляемый reverse-proxy перед приложением: вы контролируете поведение кеша на уровне HTTP, включаете фрагментный кеш через ESI, используете Grace (аналог stale-режима) и аккуратно инвалидируете объекты через purge или bans.
Главная мысль: Varnish ускоряет «массовые» ответы, но требует дисциплины. Почти все реальные проблемы на проде сводятся к трём вещам: некорректные заголовки (Cache-Control и Vary), лишние cookies у анонимов и небезопасная или хаотичная схема очистки кеша.
Зачем Varnish в 2026, если есть CDN и быстрые PHP и БД?
Даже на быстрых NVMe и современном PHP генерация HTML в WordPress — это цепочка запросов к базе данных, PHP-логика, плагины и шаблоны. Для анонимного трафика это почти всегда повторяемая работа. Varnish снимает её, отдавая готовый ответ из памяти и резко снижая нагрузку на бэкенд.
Ещё один практический кейс — API. Если у вас много одинаковых GET к справочникам, каталогам и статусам, Varnish даёт предсказуемую задержку и защищает бэкенд от «шумных» клиентов и ботов.
Сначала добейтесь корректного кеширования для анонимного пользователя по HTTP-заголовкам. ESI, Grace и тонкая логика по cookies добавляются только после того, как базовый кеш даёт стабильный HIT.
Базовая схема: WordPress, Nginx или Apache и Varnish
Классическая топология выглядит так: клиент приходит на TLS-терминацию (Nginx, HAProxy или балансировщик), дальше запрос уходит по HTTP на Varnish, затем на веб-сервер и PHP-FPM.
- клиент → TLS (Nginx или LB) → Varnish → Nginx или Apache → PHP-FPM → БД;
- админка и авторизованные пользователи обходят кеш;
- публичные страницы и часть API кешируются.
Важно помнить: Varnish кеширует только HTTP. Значит, TLS должен завершаться до него (на Nginx, HAProxy, балансировщике провайдера), либо вы строите схему с PROXY protocol и внутренней сетью, но сам Varnish HTTPS-терминацией не занимается.
Если проект растёт, Varnish логичнее выносить на отдельный узел или на отдельный слой перед приложением. Обычно под это берут отдельную VDS для слоя кеша, чтобы независимо масштабировать кеш и бэкенд.
Что именно кешировать: WordPress и API без сюрпризов
Базовое правило: кешируем то, что одинаково для всех анонимов и не зависит от персональных данных. Для WordPress это чаще всего главная, рубрики, записи, страницы, архивы, поисковая выдача (иногда), фиды (если они публичные и стабильные). Для API — публичные справочники и «каталоги», которые обновляются по расписанию.
Почти всегда стоит обходить кеш для:
- /wp-admin/ и /wp-login.php;
- страниц корзины и оформления заказа (если есть e-commerce);
- эндпоинтов, где есть персонализация или авторизация;
- POST, PUT, PATCH, DELETE (кроме очень продвинутых схем).
Для API полезно заранее договориться о семантике: если бэкенд не выставляет явные заголовки кеширования, то Varnish становится «источником правды», и ответственность за TTL ложится на инфраструктуру. Это нормально, но тогда фиксируйте политики по путям и методам в VCL.

Критичный момент: cookies ломают кеш чаще, чем TTL
WordPress и плагины любят ставить cookies «на всякий случай». Для Varnish это означает разные ключи кеша и частые MISS. Практика: для анонимного трафика вычищаем «шумные» cookies и оставляем только то, что реально влияет на контент (обычно — ничего).
Типовой подход: если нет признаков авторизации, выкидываем cookies, которые не нужны для публичного HTML. Например, очищаем всё, кроме сессионных маркеров вашего проекта (если такие вообще нужны анонимам).
Grace: стабильность при пиках и при падении бэкенда
grace позволяет Varnish отдавать «протухший» объект, пока он тихо обновляет его в фоне или пока бэкенд временно недоступен. На контентных сайтах это часто лучше, чем лавина запросов в PHP-FPM в момент, когда объект истёк.
Практический сценарий: TTL 5 минут, grace 30 минут. Если бэкенд отвечает медленно или отдаёт 5xx, Varnish продолжит отдавать старую страницу из кеша (в пределах grace), а вы выигрываете время на восстановление.
ESI: фрагментный кеш без тотальной персонализации
ESI (Edge Side Includes) полезен, когда страница в целом одинаковая, но есть один-два маленьких динамических блока: «профиль», «счётчик», «избранное», «корзина» и т.п. Тогда вы кешируете основу страницы, а динамический фрагмент подтягиваете отдельным запросом, который можно либо не кешировать, либо кешировать иначе.
Важно: ESI добавляет сложность отладки и увеличивает количество запросов. В 2026 ESI стоит включать только там, где выгода очевидна, и вы контролируете кеш-ключи для фрагментов.
Purge и bans: как правильно инвалидировать кеш
Инвалидация — самая болезненная часть. Ошибка здесь обычно приводит либо к «вечному старью», либо к случайному DDoS собственного бэкенда массовыми очистками.
- purge — точечное удаление конкретного URL (быстро и безопасно, но требует знания ключа объекта).
- bans — логическое правило «запретить» объекты по условию (гибко, но может быть дорого на больших объёмах).
Для WordPress в большинстве случаев хватает точечного purge по событиям публикации: запись, рубрика, главная, RSS. Для крупных порталов и API-каталогов иногда удобнее bans по префиксу пути или по хосту, но это нужно тестировать под реальной нагрузкой.
Безопасность purge: только из доверенной сети и с ACL
Никогда не открывайте purge «в интернет». Разрешайте очистку только с IP админских подсетей, CI/CD или с адресов вашего приложения. Также полезно требовать секретный заголовок.
Метрики и проверка на проде: что смотреть, чтобы не гадать
Чтобы Varnish приносил пользу, его нужно измерять. Минимальный набор:
- hit ratio (HIT vs MISS) по основным путям;
- частота
passи причины обхода кеша; - доля ответов с cookies у анонимов;
- ошибки бэкенда и как часто срабатывает grace.
На практике удобно добавлять отладочный заголовок (например, X-Cache: HIT|MISS) и снимать статистику по логам и APM.
Минимальный VCL-скелет: кеш анонимов, обход админки, чистка cookies
Ниже — упрощённый пример логики. Его нужно адаптировать под вашу схему доменов, статические файлы и особенности приложения.
vcl 4.1;
backend default {
.host = "127.0.0.1";
.port = "8080";
}
acl purge {
"127.0.0.1";
"10.0.0.0"/8;
"192.168.0.0"/16;
}
sub vcl_recv {
if (req.method == "PURGE") {
if (client.ip !~ purge) {
return (synth(403, "Forbidden"));
}
return (purge);
}
if (req.url ~ "^/wp-admin/" || req.url == "/wp-login.php") {
return (pass);
}
if (req.method != "GET" && req.method != "HEAD") {
return (pass);
}
if (req.http.Cookie) {
if (req.http.Cookie ~ "wordpress_logged_in_" || req.http.Cookie ~ "wp-postpass_") {
return (pass);
}
unset req.http.Cookie;
}
return (hash);
}
sub vcl_backend_response {
set beresp.ttl = 5m;
set beresp.grace = 30m;
if (beresp.http.Set-Cookie) {
set beresp.uncacheable = true;
set beresp.ttl = 0s;
return (deliver);
}
return (deliver);
}
Если используете Nginx перед Varnish для TLS, проверьте, что вы корректно прокидываете Host, X-Forwarded-For и X-Forwarded-Proto, иначе легко получить проблемы с редиректами и генерацией абсолютных URL.

Частые ловушки на проде
- Vary: Cookie от плагина или темы: гарантированный убийца hit ratio.
- Set-Cookie в публичных ответах: приводит к
passи обнулению кеша. - Слишком маленький TTL без grace: всплески нагрузки на истечении объектов.
- Плохая стратегия инвалидации: массовые bans вместо точечных purge без необходимости.
- Отсутствие явных правил для API: случайная кешируемость «как получится».
Если упираетесь в ресурсы на одном сервере (Varnish, веб-сервер, PHP-FPM и БД делят CPU и RAM), разделение ролей часто даёт мгновенный эффект: Varnish на отдельной машине, приложение отдельно. Для небольших проектов может подойти виртуальный хостинг, а когда нагрузка растёт — отдельные узлы под кеш и бэкенд.


