Почему статику лучше отдавать напрямую
Картинки, CSS, JS и шрифты не требуют выполнения PHP-кода, поэтому пропускать их через PHP-FPM — трата ресурсов. Nginx умеет отдавать файлы с диска напрямую, в разы быстрее и с меньшей нагрузкой на сервер. Задача администратора — правильно указать Nginx, какие пути обслуживать напрямую, а какие передавать бэкенду.
Как работает try_files
Директива try_files проверяет файлы и каталоги по порядку и отдаёт первый найденный, а если ничего не найдено — передаёт запрос дальше:
location / {
root /var/www/example.com/public;
try_files $uri $uri/ /index.php?$query_string;
}Здесь Nginx сначала ищет файл с точным именем запроса, потом каталог с таким именем, и только если ничего не нашлось — передаёт запрос в index.php. Это стандартная схема для WordPress, Laravel и большинства современных PHP-приложений.
Как отдавать статику отдельным location
Для статических файлов имеет смысл выделить отдельный блок с собственными настройками кэширования:
location ~* \.(jpg|jpeg|png|gif|webp|svg|css|js|woff2?)$ {
root /var/www/example.com/public;
try_files $uri =404;
expires 30d;
add_header Cache-Control "public, immutable";
access_log off;
}Параметр access_log off для статики снижает нагрузку на диск: незачем писать в лог тысячи запросов картинок и скриптов.
Директивы кэширования и производительности
| Директива | Значение | Эффект |
|---|---|---|
| expires | 30d, 1y | Заголовок Cache-Control и Expires для браузера |
| sendfile | on | Отдача файла через системный вызов sendfile, без копирования в память Nginx |
| tcp_nopush | on | Отправка заголовков и начала файла одним TCP-пакетом |
| open_file_cache | max=1000 inactive=20s | Кэш дескрипторов файлов и метаданных, чтобы не читать диск повторно |
Директивы sendfile и tcp_nopush включают в секции http {} один раз — они действуют глобально и не требуют настройки на каждый сайт.
Как настроить open_file_cache
На сайтах с большим числом мелких файлов — иконки, аватары, миниатюры — полезно включить кэш дескрипторов:
open_file_cache max=2000 inactive=30s;
open_file_cache_valid 60s;
open_file_cache_min_uses 2;
open_file_cache_errors on;Это уменьшает число системных вызовов open() и stat() для файлов, которые запрашивают часто: Nginx хранит их дескрипторы в памяти вместо повторного чтения с диска.
Частые ошибки при отдаче статики
Что чаще всего ломает раздачу статики:
- слишком долгий
expiresдля файлов без версионирования в имени — обновлённый CSS не долетит до пользователя - регулярное выражение в location без экранирования точки — совпадёт с лишними путями
- отсутствие
try_files $uri =404;— запрос на несуществующий файл уйдёт в PHP-FPM зря - root, указанный в двух разных местах конфигурации с разными путями — типичная причина 404 на статике
Итог
Чек-лист для быстрой отдачи статики:
- вынести статические расширения в отдельный location с try_files $uri =404;
- задать expires от 30 дней и Cache-Control: immutable для файлов с версией в имени
- включить sendfile, tcp_nopush и open_file_cache в http {}
- отключить access_log для статики, чтобы не грузить диск
После настройки статики стоит проверить сжатие ответов через gzip и Brotli и включить поддержку HTTP/2 и HTTP/3 — вместе с try_files и expires это даёт основной прирост скорости сайта.