Как ускорить статический сайт в Nginx без лишних трюков
Скорость статического сайта в Nginx упирается не только в железо. Разбираем кеширование, сжатие, sendfile, заголовки и проверку результата — на конфигурации для Nginx 1.26.x.

Статический сайт на Nginx может отдавать HTML, CSS, JavaScript и изображения почти без нагрузки на CPU, но это не происходит автоматически. Неправильные заголовки кеширования заставляют браузер скачивать файлы заново, сжатие увеличивает время ответа, а отсутствие предварительной проверки превращает «быстрый» сервер в источник случайных задержек. Ниже — практическая конфигурация для Nginx 1.26.x и критерии, по которым можно понять, что ускорение действительно сработало.
Сначала измерьте, а потом меняйте конфигурацию
Не начинайте с десятка директив из чужого конфигурационного файла. Зафиксируйте исходные значения для главной страницы, одного CSS-файла и крупного изображения. Проверяйте сайт с той же точки сети, откуда обычно приходят пользователи: локальный запрос к серверу не показывает задержку между дата-центром и клиентом.
- время до первого байта для HTML;
- размер ответа до и после сжатия;
- наличие
Cache-Control,ETagиContent-Encoding; - долю ответов с кодами 4xx и 5xx;
- время загрузки главного CSS и JavaScript после очистки кеша.
Для отдельных запросов достаточно DevTools в браузере и команды curl -I. Для нагрузки используйте инструмент, который уже принят в вашей команде, и указывайте условия теста: размер файлов, число параллельных запросов, тип диска и сетевую задержку. Универсального числа «Nginx должен отвечать за X миллисекунд» не существует.
Максимальная скорость статического сайта начинается не с более мощного сервера, а с ответа, который не нужно повторно скачивать.
Базовая конфигурация для статических файлов
Ниже приведён фрагмент для сайта, собранного в каталог /srv/www/site/dist. Он рассчитан на Nginx 1.26.x. Пути, домен и параметры TLS подставьте свои. Директивы sendfile, tcp_nopush и open_file_cache относятся к отдаче файлов и не заменяют настройку TLS или CDN.
http {
sendfile on;
tcp_nopush on;
keepalive_timeout 65;
gzip on;
gzip_vary on;
gzip_comp_level 5;
gzip_min_length 1024;
gzip_types
text/plain
text/css
application/javascript
application/json
application/xml
image/svg+xml;
open_file_cache max=1000 inactive=30s;
open_file_cache_valid 60s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
server {
listen 443 ssl;
server_name example.com;
root /srv/www/site/dist;
index index.html;
location = / {
try_files /index.html =404;
add_header Cache-Control "no-cache" always;
}
location ~* \\.(?:css|js|mjs|svg|woff2|png|jpg|jpeg|webp|avif)$ {
try_files $uri =404;
add_header Cache-Control "public, max-age=31536000, immutable" always;
}
location / {
try_files $uri $uri/ =404;
add_header Cache-Control "no-cache" always;
}
}
}
После изменения проверьте конфигурацию командой nginx -t, затем перечитайте её штатным способом, принятым в вашей системе. Если в дистрибутиве директива или модуль недоступны, Nginx сообщит об этом на проверке, а не во время запроса.
Что именно ускоряет отдачу
Кеширование файлов с хешем в имени
Для файлов вроде app.8f31c2.js можно использовать долгий кеш: после новой сборки имя изменится, и браузер запросит новый ресурс. Параметр immutable сообщает, что браузеру не нужно перепроверять такой файл в течение указанного срока. Это безопасно только для действительно версионированных файлов.
HTML обычно оставляют с no-cache. Это не запрещает браузеру хранить документ, а требует проверить его актуальность перед повторным использованием. Если поставить годовой кеш на index.html без смены URL, пользователи могут видеть старую ссылку на JavaScript после релиза.
Сжатие без попытки сжать всё
Nginx сжимает ответы указанных MIME-типов на лету. HTML, CSS, JavaScript, JSON и SVG обычно выигрывают от gzip. JPEG, PNG, WebP, AVIF, архивы и шрифты уже сжаты или близки к этому: повторное сжатие тратит CPU, но почти не уменьшает ответ.
Уровень gzip_comp_level 5 — компромисс, а не магическое оптимальное значение. Увеличение уровня может уменьшить файл, но повысить расход CPU. Сравнивайте размер и время ответа на вашем наборе файлов, а не на одном маленьком тестовом документе.
sendfile и буферизация ядра
sendfile on позволяет передавать содержимое файла между файловой системой и сокетом с меньшим количеством копирований через пространство пользовательского процесса. tcp_nopush on помогает собирать заголовки и начало ответа в более крупные сетевые сегменты при использовании sendfile. Эффект зависит от ОС, файловой системы и размера объектов, поэтому его нужно проверять измерением.
Кеш открытых файлов
open_file_cache хранит сведения об открытых файлах, их размерах и ошибках доступа. Это полезно для сайта с большим числом небольших объектов, когда Nginx часто обращается к одной и той же директории. Параметр inactive не означает срок жизни кеша: он задаёт время, после которого неиспользуемая запись может быть удалена.
Не ставьте огромный max вслепую. Кеш занимает память, а слишком агрессивное кеширование ошибок может замедлить восстановление после появления файла. Значения из примера — стартовая точка для проверки, а не обязательный стандарт.
Сравнение подходов
«Максимум скорости» достигается не одной директивой. У каждого слоя есть цена: кеширование ускоряет повторные визиты, но усложняет публикацию; gzip экономит трафик, но использует CPU; CDN сокращает сетевую задержку, но добавляет ещё один кеш и отдельную настройку очистки.
| Подход | Что ускоряет | Цена и риск | Когда применять |
|---|---|---|---|
| Долгий кеш хешированных ресурсов | Повторную загрузку CSS, JS, шрифтов и изображений | Ошибки публикации при неизменяемых именах файлов | Почти всегда для сборок с fingerprint в имени |
| Gzip на Nginx | Передачу текстовых ответов | Расход CPU на каждый незакешированный ответ | Если нет готовых сжатых файлов или CDN |
| Предварительно сжатые файлы | Время CPU при отдаче популярных ресурсов | Нужны шаг сборки и дополнительный контроль файлов | При заметной нагрузке или дорогом CPU |
| CDN | Задержку и нагрузку на исходный сервер | Настройка DNS, кеша и очистки объектов | Для пользователей из разных регионов |
| open_file_cache | Повторные обращения к локальной файловой системе | Расход памяти и риск устаревших метаданных | При большом числе мелких файлов и частых запросах |
Когда конфигурация ломается
- Новая версия сайта не появляется. Проверьте, не получил ли
index.htmlдолгий кеш и не осталось ли старое имя ресурса в HTML. - В ответе нет gzip. Убедитесь, что клиент отправляет
Accept-Encoding: gzip, тип ответа есть вgzip_types, а размер превышаетgzip_min_length. - Вместо страницы возвращается 404. Проверьте
root, регистр имени файла и результатtry_files. Для обычного статического сайта не добавляйте fallback наindex.html, если маршрутизацию выполняет не браузерное приложение. - Настройки заголовков пропали. В Nginx директива
add_headerна более внутреннем уровне может изменить ожидаемое наследование. Смотрите фактический ответ черезcurl -I, а не только конфигурацию. - Сжатие увеличило задержку. Сравните CPU и размер ответа. Для небольших файлов выгода может быть меньше стоимости компрессии, а для уже сжатых изображений её обычно нет.
Где подход ломается
Долгий кеш не исправит тяжёлую картинку, не уменьшит количество JavaScript и не ускорит запрос к внешнему API. Если сервер отвечает быстро, а страница всё равно долго становится интерактивной, ищите проблему в размере ресурсов, порядке их загрузки и работе браузера.
Не смешивайте две задачи: инвалидация кеша CDN и настройка Nginx требуют отдельных правил. Также не включайте Brotli только потому, что увидели такую директиву в чужом примере: в стандартной сборке Nginx нужного модуля может не быть. Используйте его только после проверки состава вашей сборки и официальной документации модуля.
Сноска. ETag — HTTP-заголовок с идентификатором версии ресурса. Браузер может отправить его обратно, чтобы сервер ответил коротким кодом 304, если файл не изменился.
Что проверить после публикации
Сделайте отдельный прогон после каждого изменения конфигурации и сборки сайта. Проверьте HTML без кеша, повторный визит с кешем, запрос с поддержкой gzip и запрос к отсутствующему файлу. Затем сравните не только среднее время, но и худшие значения задержки: именно они заметны пользователям с медленной сетью.
- Выполните
nginx -tи убедитесь, что конфигурация проходит проверку. - Проверьте заголовки HTML и статического ресурса через
curl -I https://example.com/. - Убедитесь, что хешированные файлы получают долгий кеш, а HTML — проверку актуальности.
- Сравните размер ответа с
Accept-Encoding: gzipи без него. - Поставьте мониторинг кодов 4xx/5xx, времени до первого байта и загрузки главного HTML.
Следующим шагом измерьте реальный трафик по типам файлов. Если основную долю занимают изображения, настройка gzip не даст заметного результата — потребуется оптимизация изображений или CDN. Если преобладают небольшие CSS и JavaScript, сначала проверьте хеширование имён и заголовки кеша, а уже потом увеличивайте параметры Nginx.
Проверка рекламы на риски: Что в макете вызовет вопросы ФАС: превосходные степени, сравнения, обещания результата, маркировка.
Спросить за 40 ₽Источники: Nginx documentation: ngx_http_gzip_module, Nginx documentation: ngx_http_core_module
Частые вопросы
Нужно ли включать gzip для статического сайта?
Можно ли поставить max-age на один год для всех файлов?
Почему после настройки Nginx сайт не стал быстрее?
Нужен ли CDN, если сайт уже быстро отвечает из Nginx?
Что делать, если после изменения кеша пользователи видят старую версию?
Можно ли включить open_file_cache на любом сервере?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.