Как использовать Cache-Control в NGINX

HTTP заголовок Cache-control сообщает браузеру сохранить определенные файлы с сайта в кеше браузера, чтобы при повторном обращении браузер использовал кеш вместо запроса к сайту.

Это позволяет значительно увеличить скорость загрузки сайта для людей, которые смотрят более одной страницы, а также сократить кол-во запросов к серверу.

Cache-Control

Cache-Control имеет несколько вариантов работы:

public — может быть кэширован кем угодно, включая браузеры и CDN. Используется для большинства статических объектов.

private — содержит конфиденциальные данные, которые не могут быть кэшированы CDN или обратными прокси. Браузер пользователя может кэшировать их локально. Используйте этот параметр для аутентифицированных страниц (например где пользователь меняет персональные данные).

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

no-store — полностью отключает кэширование. Используйте этот параметр только для очень чувствительных данных.

max-age

Зто время, на которое будет закэширован результат. Устанавливается в секундах. Однако NGINX допускает несколько дополнительных пользовательских значений:

-1 or off — отключает кэширование и не изменяет существующие заголовки
epoch — задаёт время “Thu, 01 Jan 1970 00:00:01 GMT” (1 января 1970 00:00:01 GMT) для поля “Expires” и “no-cache” для поля “Cache-Control”. Полезно ставить этот параметр, если вы используете NGINX в качестве обратного прокси
max — задаёт время “Thu, 31 Dec 2037 23:55:55 GMT” (31 декабря 2037 23:55:55 GMT) для поля “Expires” и 10 лет для поля “Cache-Control”.
30s — задает секунды
1m — задает минуты
24h — задает часы
3d — задает дни
1M — задает месяцы
2y — задает года

Кроме того, можно добавить директиву no-transform, которая отключает любые преобразования, которые могут быть выполнены с ресурсом. Например, некоторые CDN сжимают изображения для уменьшения пропускной способности. Эта директива отключает такое поведение.

Использоваение Cache-Control и max-age

Для NGINX вы можете изменить заголовки Cache-Control с помощью следующих директив:

expires 1y;
add_header Cache-Control "public, no-transform";

Первая строка устанавливает max-age на 1 год, а вторая — настройки кэширования public и no-transform.

Вы можете добавить это в блок server, чтобы применять по всему сайту, но лучшим методом является сопоставление расширений файлов.

Чтобы установить различные значения в зависимости от расширения файла используется следующий формат:

location ~* .(?:css|js)$ {
   expires 1y;
   add_header Cache-Control "public";
}

В этом блоке расположения используется совпадение регулярных выражений, обозначаемое символом ~. Это полезно для применения общих настроек типа содержимого.

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

location /profile {
   expires 2d;
   add_header Cache-Control "public, no-transform";
}

Вы также можете использовать модификатор =, который точно соответствует путям и будет иметь приоритет над regex-соответствием и стандартным блоком расположения.

Использование Surrogate-Control для изменения поведения CDN

Хотя вы можете отключить кэширование CDN и по-прежнему использовать кэширование браузера с помощью Cache-Control: private, лучше иметь прямой контроль над ним. Большинство CDN будут уважать заголовок Surrogate-Control, который функционирует точно так же, как Cache-Control, только предназначен только для CDN. Таким образом, вы можете сказать Fastly делать одно, а пользователю — другое.

В NGINX вам придется устанавливать этот заголовок вручную и задавать значение max-age вместо использования директивы expires NGINX.

add_header Surrogate-Control "public, max-age=86400";
add_header Cache-Control "public, max-age=120";

Вам обязательно нужно протестировать свою CDN, чтобы убедиться, что это работает — Surrogate-Control появился довольно недавно и не является универсальным.