Зачем вообще нужен кеш

Когда пользователь открывает страницу, браузер запрашивает десятки файлов: HTML, CSS, JavaScript, картинки, шрифты. Каждый запрос — это время. Если сервер находится в Москве, а пользователь во Владивостоке, задержка составляет 140–200 мс только на передачу одного пакета. Умножь на количество файлов — и получишь сайт, который грузится три-четыре секунды.

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

Это влияет не только на скорость, но и на нагрузку сервера. Меньше запросов — меньше CPU и памяти тратится на обработку. Для сайтов с тысячами посетителей в день разница ощутимая.

Виды кеширования: что где живёт

Кеш бывает на разных уровнях, и каждый работает по-своему.

Браузерный кеш — файлы сохраняются прямо на компьютере или телефоне пользователя. Управляется HTTP-заголовками, которые отдаёт сервер.

Серверный кеш — сервер сохраняет готовые HTML-страницы или результаты запросов к базе данных, чтобы не генерировать их каждый раз заново. Типичные инструменты — Nginx FastCGI Cache, Varnish, Redis, Memcached.

CDN (Content Delivery Network) — сеть распределённых серверов по всему миру. Статические файлы (картинки, CSS, JS) хранятся на ближайшем к пользователю узле. Cloudflare, Fastly, AWS CloudFront — популярные варианты.

Кеш приложения — внутри кода. Например, результат тяжёлого SQL-запроса сохраняется в Redis на 5 минут, и следующая тысяча пользователей получает его мгновенно.

Хорошо настроенный сайт использует все четыре уровня. Но начинать стоит с браузерного — он самый простой и даёт ощутимый результат сразу.

HTTP-заголовки кеширования: основа основ

Браузер понимает кеш через заголовки, которые сервер отправляет вместе с файлом.

Cache-Control

Главный заголовок. Говорит браузеру, как долго хранить файл и при каких условиях:

Cache-Control: max-age=31536000, immutable

max-age=31536000 — хранить год (в секундах). Подходит для статики, которая не меняется: шрифты, библиотеки. immutable говорит браузеру, что файл точно не изменится даже при ручном обновлении страницы.

Cache-Control: no-cache

Не означает «не кешировать». Означает «каждый раз проверяй у сервера, не изменился ли файл». Если не изменился — берёт из кеша.

Cache-Control: no-store

Вот это уже «никогда не сохранять». Подходит для страниц с личными данными, банковских форм.

Cache-Control: public, max-age=86400

public разрешает кешировать промежуточным серверам (CDN, прокси). max-age=86400 — сутки.

Cache-Control: private, max-age=3600

private — только браузер, CDN не кешируют. Например, для страниц профиля пользователя.

ETag и Last-Modified

Эти заголовки работают в паре с no-cache. Сервер отдаёт файл с меткой:

ETag: "abc123"
Last-Modified: Wed, 01 Jan 2026 12:00:00 GMT

При следующем запросе браузер спрашивает: «Файл с этой меткой ещё актуален?» Если да — сервер возвращает 304 Not Modified без тела, и браузер достаёт файл из кеша. Экономия трафика и времени без лишней нагрузки на канал.

Как настроить кеш в Nginx

Если сайт работает на Nginx, базовые настройки кеширования добавляются в конфиг за несколько минут:

location ~* \.(css|js|woff2|woff|ttf)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
}

location ~* \.(jpg|jpeg|png|gif|webp|svg|ico)$ {
    expires 30d;
    add_header Cache-Control "public";
}

location ~* \.(html|htm)$ {
    expires 1h;
    add_header Cache-Control "public, must-revalidate";
}

Шрифты и библиотеки — год, они не меняются. Картинки — месяц. HTML — час, потому что контент меняется чаще.

Важный момент: если CSS-файл закешировался на год, а ты его изменил — пользователь не увидит изменений до истечения срока. Решение — cache busting: добавлять хеш к имени файла при сборке. style.css превращается в style.abc123.css. Новый файл — новый URL — браузер скачает его заново. Большинство сборщиков (Webpack, Vite) делают это автоматически.

Серверный кеш страниц

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

Nginx FastCGI Cache

Если сайт на PHP (WordPress, Laravel), можно включить FastCGI Cache:

fastcgi_cache_path /var/cache/nginx levels=1:2 keys_zone=SITE:100m inactive=60m;
fastcgi_cache_key "$scheme$request_method$host$request_uri";

server {
    set $skip_cache 0;

    if ($http_cookie ~* "wordpress_logged_in") {
        set $skip_cache 1;
    }

    if ($request_uri ~* "/(cart|checkout|my-account)") {
        set $skip_cache 1;
    }

    location ~ \.php$ {
        fastcgi_cache SITE;
        fastcgi_cache_valid 200 60m;
        fastcgi_cache_bypass $skip_cache;
        fastcgi_no_cache $skip_cache;
    }
}

Авторизованным пользователям и страницам корзины кеш не нужен — у них динамический контент. Это базовая схема, её нужно дополнять под конкретный проект.

Redis для кеша данных

Redis — in-memory хранилище, которое работает как сверхбыстрая база данных. Типичный сценарий: результат запроса к базе (например, список товаров) сохраняется в Redis на несколько минут.

import redis
import json

r = redis.Redis(host='localhost', port=6379, db=0)

def get_products():
    cache_key = 'products_list'
    cached = r.get(cache_key)

    if cached:
        return json.loads(cached)

    products = db.query("SELECT * FROM products WHERE active = 1")
    r.setex(cache_key, 600, json.dumps(products))  # 600 секунд
    return products

Паттерн называется Cache-Aside (Lazy Loading): сначала смотрим в кеш, при промахе идём в базу.

Главный вопрос при работе с Redis — инвалидация. Когда менеджер обновляет товар в админке, нужно сбросить соответствующий ключ:

r.delete('products_list')

Если забыть — пользователи видят устаревшие данные.

CDN: кеш на краю сети

CDN особенно важен, если аудитория разбросана географически. Cloudflare бесплатно кеширует статику и распределяет её по 200+ точкам присутствия по всему миру.

Базовая настройка через Cache Rules в Cloudflare:

  • Статика (CSS, JS, изображения) — Edge Cache TTL: 1 месяц
  • HTML-страницы блога — Edge Cache TTL: 4 часа
  • Страницы с динамическим контентом — Bypass Cache

После включения CDN скорость загрузки для пользователей из дальних регионов может вырасти в 2–3 раза. Latency от Москвы до Владивостока составляет ~140 мс, от ближайшего узла Cloudflare — 15–20 мс. Разница прямая.

Кеш в WordPress

WordPress без кеша — это боль. Каждый запрос страницы генерирует 30–80 запросов к базе данных. При небольшом трафике терпимо, при нагрузке сервер ложится.

Популярные плагины кеширования:

  • WP Rocket — платный, самый удобный, настраивается за 15 минут
  • W3 Total Cache — бесплатный, много настроек, легко запутаться
  • LiteSpeed Cache — если хостинг использует LiteSpeed

Что включить в любом из них:

  1. Page Cache — сохраняет готовый HTML
  2. Минификация CSS и JS — меньше файлов, меньше запросов
  3. Lazy loading изображений — грузить картинки по мере прокрутки
  4. Database Cache — через Redis или Memcached

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

Что точно не надо кешировать

Кеш не везде помогает. Список того, что кешировать опасно:

  • Страницы авторизованных пользователей (профиль, история заказов)
  • Корзина и процесс оформления заказа
  • Страницы с CSRF-токенами
  • API-ответы с персональными данными
  • Страницы с данными реального времени (котировки, чаты)

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

Как убедиться, что кеш работает

Самый простой способ — заголовки ответа в DevTools. Открой вкладку Network, найди нужный файл и посмотри Response Headers:

  • Cache-Control: max-age=31536000 — кеш настроен
  • cf-cache-status: HIT — файл отдан из кеша Cloudflare
  • Status: 304 Not Modified — браузер использовал локальный кеш

Google PageSpeed Insights прямо указывает файлы без кеширования или с коротким TTL в разделе «Эффективно используйте кеш браузера».

Для проверки серверного кеша Nginx можно добавить отладочный заголовок:

add_header X-Cache-Status $upstream_cache_status;

Он покажет HIT, MISS, BYPASS или EXPIRED для каждого запроса.

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

Слишком длинный TTL для HTML. Закешировал главную страницу на неделю, обновил акцию — пользователи неделю видят старую. Для HTML разумный максимум — несколько часов.

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

Нет инвалидации. Обновил товар, но забыл сбросить кеш. Половина пользователей видит старую цену, половина — новую.

Cache busting не настроен. Обновил CSS, имя файла не изменилось. Пользователи с долгим кешем видят сломанную верстку.

Кешируются ошибки. Сервер вернул 500, CDN закешировал ошибку на час. Теперь тысячи пользователей видят ошибку даже после её исправления. Никогда не кешируй ответы с кодами 4xx и 5xx — большинство CDN делают это правильно по умолчанию, но стоит проверить явно.


Кеширование — одна из тех вещей, которые при правильной настройке работают незаметно, но без них сайт ощущается медленным и нагружает сервер впустую. В REEXY вопрос кеша решается на этапе разработки: конфиги Nginx, Redis и базовая настройка CDN входят в стандартный процесс. Но даже если сайт уже готов, большинство изменений из этой статьи можно внедрить самостоятельно за пару часов — главное, не забыть проверить результат через DevTools.