nginx: Expires и Cache-Control для статических файлов
Введение
Это руководство объясняет, как в nginx задать заголовок Expires и директиву max-age заголовка Cache-Control для статических файлов (изображения, CSS, JavaScript). Правильная настройка позволяет браузерам посетителей кэшировать ресурсы на стороне клиента, экономя пропускную способность и ускоряя повторные посещения сайта.
Важно: кэширование имеет смысл только для неизменяемых или версионированных ресурсов. Если файл будет изменён без смены имени, браузеры не обновят его автоматически.
Предварительная заметка
Предполагается, что у вас уже есть рабочая конфигурация nginx (LEMP или другая), и вы умеете перезагружать сервис после правок. Если нет — сначала настройте nginx и PHP/MariaDB по подходящему руководству для вашей ОС.
Настройка nginx
Директива expires позволяет задавать Expires и управлять Cache-Control. Её можно поместить внутрь блоков http {}, server {}, location {} или в if внутри location {}. Чаще всего её используют в location для статических файлов:
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
expires 365d;
}В этом примере всем файлам с расширениями .jpg, .jpeg, .png, .gif, .ico, .css и .js добавляется заголовок Expires через 365 дней от времени доступа браузера. Убедитесь, что такой блок действительно обслуживает только статические ресурсы.
Для применения изменений перезагрузите nginx:
/etc/init.d/nginx reloadЧто умеет expires
- off — не изменять заголовки Expires и Cache-Control.
- epoch — установить Expires в 1 января 1970 00:00:01 GMT.
- max — установить Expires на 31 декабря 2037 23:59:59 GMT и Cache-Control: max-age равный примерно 10 годам.
- Время без префикса @ — относительное к моменту доступа браузера. Можно указать отрицательное значение, чтобы задать no-cache: например, expires -1s; или expires 0;
- Время с префиксом @ — абсолютное время суток в форме Hh или Hh:Mm (например, expires @15:34;).
Доступные единицы времени:
- ms — миллисекунды
- s — секунды
- m — минуты
- h — часы
- d — дни
- w — недели
- M — месяцы (30 дней)
- y — годы (365 дней)
Примеры: 1h30m — 1 час 30 минут, 1y6M — 1 год и 6 месяцев.
expire на основе даты изменения файла
Если ресурс хранится как реальный файл на диске, можно основать заголовок на дате модификации файла:
expires modified 10d;Это удобно для файлов, которые обновляются редко, но при этом хотят задать срок жизни относительно времени изменения.
Важно: директива modified работает только для реальных файлов, а не для виртуальных ответов, генерируемых приложениями.
Практические рекомендации и лучшие практики
- Всегда версионируйте изменяемые статические файлы: app.js → app-1.1.js или app.v202511.js. Это простая и надёжная стратегия принуждения браузеров скачать новую версию.
- Устанавливайте короткий срок жизни для динамических и персонализированных ресурсов.
- Никогда не кэшируйте чувствительные или приватные данные (страницы профиля, ответы, содержащие PII) — используйте заголовки Cache-Control: no-store, no-cache.
- Сочетайте long-term кэширование статических ресурсов с контролем версии — это оптимальный компромисс производительности и безопасности.
Примеры конфигураций (шаблоны)
Шаблон для общих статических ресурсов:
location ~* \.(?:css|js|jpg|jpeg|png|gif|ico|svg)$ {
expires 30d;
add_header Cache-Control "public, max-age=2592000";
}Шаблон для неизменяемых ресурсов с версией в имени (долгий кэш):
location ~* \.(?:css|js|jpg|jpeg|png|gif|ico|svg)$ {
expires 365d;
add_header Cache-Control "public, max-age=31536000, immutable";
}Обратите внимание: директива add_header управляет заголовками вручную и может понадобиться в особых случаях. Параметр immutable информирует поддерживающие браузеры, что ресурс никогда не изменится.
Тестирование
Проверьте заголовки через инструменты разработчика браузера (Network) или с помощью curl:
curl -I https://example.com/path/to/image.pngВ ответе вы должны увидеть строки типа:
- Expires: Wed, 13 Nov 2026 12:00:00 GMT
- Cache-Control: max-age=31536000
Пример скриншота заголовков в Firefox:

Когда это не работает (контрпримеры)
- Файл отдаётся динамическим обработчиком (процессор, который формирует ответ на лету) — expires modified не сработает.
- CDN поверх вашего сервера может перезаписать или игнорировать заголовки. Согласуйте настройки с CDN или укажите нужные правила там.
- Неправильный location-блок или порядок правил в конфигурации nginx может приводить к тому, что правило не применяется — используйте nginx -T для отладки.
- Если вы забыли версионировать файл, браузеры продолжат использовать старую версию до истечения срока кэша.
Альтернативные подходы
- Управление кэшированием на уровне CDN — возможно, более гибкое и масштабируемое решение.
- Добавление контрольных сумм (hash) в имена файлов при сборке ассетов (webpack, gulp) — автоматическая версия при каждом сборке.
- Использование Service Workers для продвинутого кэширования на стороне клиента (PWA-подход).
Роли и чек-листы по внедрению
DevOps:
- Добавить правила expires в nginx-конфигурацию.
- Перезагрузить nginx безопасно (reload, проверка конфигурации nginx -t).
- Протестировать заголовки curl и в браузере.
Frontend-разработчик:
- Включить версионирование имён файлов в сборочной цепочке.
- Проверить поддержку immutable и совместимость с CI/CD.
QA:
- Проверить, что страницы с приватными данными не кэшируются.
- Проверить, что новая версия ресурса загружается после смены имени файла.
Мини-методология внедрения (шаг за шагом)
- Проанализируйте список статических ресурсов и решите, какие можно кэшировать долго.
- Добавьте блок location в конфиг nginx с expires для выбранных типов файлов.
- Примените конфигурацию и проверьте nginx -t, затем reload.
- Протестируйте с curl и в браузере; проверьте работу через CDN.
- Настройте процесс сборки фронтенда на добавление хэшей/версий в имена файлов.
- Мониторьте инциденты, связанные с устаревшими ассетами, и обновляйте процедуру при релизах.
Факт-бокс — полезные числа
- 1 год = 31536000 секунд (примерное значение, используется в директиве max-age).
- 10 лет (значение, используемое директивой max) ≈ 315360000 секунд.
- units: ms, s, m, h, d, w, M (30d), y (365d).
Критерии приёмки
- Заголовки Expires и/или Cache-Control присутствуют для всех целевых статических ресурсов.
- Для версионируемых файлов срок кэширования установлен в long-term (например, 365d) и новый файл скачивается при смене имени.
- Никогда не кэшируются приватные страницы.
Советы по безопасности и конфиденциальности
- Не добавляйте заголовки долгого кэширования к ответам, содержащим персональные данные.
- При использовании CDN убедитесь, что правила кэширования не приводят к утечке пользовательских данных (учёт cookie и заголовков).
Справка и глоссарий
- Expires — HTTP-заголовок с датой, после которой ресурс считается устаревшим.
- Cache-Control — директива управления кэшированием; max-age указывает время жизни в секундах.
- Версионирование — практический приём смены имени файла при изменении содержимого, чтобы принудить скачивание новой копии.
Ссылки
- nginx HttpHeadersModule: http://wiki.nginx.org/HttpHeadersModule
Об авторе
Falko Timme — владелец Timme Hosting и главный поддерживающий HowtoForge. Один из разработчиков ISPConfig и автор материалов по администрированию Linux.
Краткое резюме
- Используйте expires в nginx для управления Expires и Cache-Control.
- Версионируйте файлы, если используете дальнюю дату истечения.
- Тестируйте через curl и инструменты разработчика браузера.
- Не кэшируйте приватные данные и согласуйте правила с CDN при использовании.
Похожие материалы
Несколько аккаунтов Skype: Multi Skype Launcher
Журнал для работы: повысить продуктивность
Персональные звуки уведомлений на Android
Скачивание шоу Hulu для офлайн‑просмотра
Microsoft Start: персонализированная новостная лента