Обслуживание статических файлов с Nginx: советы по оптимизации
Оптимизируйте доставку статических файлов Nginx с помощью правильных заголовков кэша, сжатия Gzip, безопасных настроек по умолчанию и советов по защите скрытых файлов — для более быстрых сайтов с меньшим количеством проблем с устаревшими активами.
Обслуживание статических файлов с Nginx: советы по оптимизации
Обслуживание статических файлов с Nginx — один из самых распространенных и эффективных способов доставки изображений, CSS, JavaScript, загрузок и готовых фронтенд-ресурсов. Nginx отлично справляется с этой задачей, но несколько настроек конфигурации могут стать решающим фактором между быстрым, предсказуемым сайтом и тем, который тратит пропускную способность или отдает устаревший контент.
Оптимизация статических файлов в основном касается четких путей, правильных заголовков кэширования, сжатия и безопасных настроек по умолчанию. Вам не нужна сложная настройка для достижения хороших результатов, но правила кэширования должны соответствовать тому, как именуются и развертываются ваши файлы.
Начните с четкого расположения статических файлов
Самая простая настройка статических файлов использует root и try_files:
server {
listen 80;
server_name example.com;
root /var/www/example.com/public;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
С такой конфигурацией запрос к /css/app.css отображается на /var/www/example.com/public/css/app.css. Если файл не существует, Nginx возвращает 404.
Это прямое отображение полезно при отладке. Вы можете взять URL из браузера, преобразовать его в путь файловой системы и проверить, существует ли файл:
ls -l /var/www/example.com/public/css/app.css
Если файл существует, но Nginx возвращает 404, ищите другой root, более конкретный блок location или включаемый файл, который переопределяет путь.
Для одностраничного приложения вы можете захотеть, чтобы неизвестные маршруты возвращали index.html:
location / {
try_files $uri $uri/ /index.html;
}
Это полезно для фронтенд-роутеров, но не используйте это вслепую для каждого сайта. Если отсутствующие ресурсы также возвращают index.html, отладка сломанных путей к JavaScript или изображениям может стать запутанной. Многие команды используют отдельное расположение для ресурсов, чтобы отсутствующие файлы все равно возвращали настоящий 404.
Вы также можете использовать alias, когда путь URL должен отображаться на другой путь файловой системы:
location /assets/ {
alias /srv/shared-assets/;
}
Будьте осторожны с завершающими слешами. При использовании alias путь расположения и путь файловой системы обычно должны заканчиваться на /. Несоответствие может привести к неожиданным путям к файлам.
Один безопасный шаблон:
location /downloads/ {
alias /srv/downloads/;
try_files $uri =404;
}
Здесь /downloads/manual.pdf отображается на /srv/downloads/manual.pdf. Без дисциплины в завершающих слешах легко случайно построить пути, которые не существуют, или открыть каталог, который вы не собирались публиковать.
Для более глубокого изучения поведения сопоставления см. Блоки location в Nginx.
Добавьте заголовки кэширования браузера
Статические файлы — отличные кандидаты для кэширования в браузере. Если пользователь загрузил app.css один раз, браузер не должен загружать его снова при каждом просмотре страницы, если он не изменился.
Для версионированных ресурсов используйте длительное время жизни кэша:
location /assets/ {
root /var/www/example.com/public;
expires 1y;
add_header Cache-Control "public, immutable";
}
Это лучше всего работает, когда имена файлов меняются во время развертывания, например, app.8f3a91.css или bundle.20260523.js. Если имя файла меняется при изменении содержимого, браузеры могут безопасно кэшировать старый файл на долгое время.
Для файлов, которые сохраняют одно и то же имя, используйте более короткое кэширование:
location = /index.html {
root /var/www/example.com/public;
expires -1;
add_header Cache-Control "no-cache";
}
Этот шаблон распространен для фронтенд-приложений. HTML-файл остается свежим, в то время как хэшированные CSS и JavaScript файлы кэшируются агрессивно.
Практический пример: ваше приложение React или Vue выводит хэшированные ресурсы в /assets/ и простой index.html. Кэшируйте /assets/ на год, но заставьте index.html перепроверяться. Пользователи получают быстрые повторные посещения, а новые развертывания все равно загружают самые новые ссылки на ресурсы.
После изменения правил кэширования проверьте заголовки, а не гадайте:
curl -I https://example.com/assets/app.8f3a91.css
curl -I https://example.com/
Вы хотите, чтобы хэшированный ресурс показывал долгоживущее значение Cache-Control. Обычно вы хотите, чтобы HTML-страница перепроверялась или использовала короткое время жизни. Если оба кэшируются на год, развертывание может оставить пользователей на старом HTML-файле, который ссылается на старый JavaScript.
Используйте сжатие для текстовых ресурсов
Текстовые ресурсы, такие как CSS, JavaScript, SVG и JSON, хорошо сжимаются. Вы можете включить Gzip в блоке http:
gzip on;
gzip_comp_level 5;
gzip_min_length 1024;
gzip_vary on;
gzip_types
text/css
application/javascript
application/json
image/svg+xml;
Не ожидайте, что Gzip сильно поможет с JPEG, PNG, WebP, MP4 или zip-файлами. Эти форматы уже сжаты. Попытка сжать их снова обычно тратит процессорное время.
Для высоконагруженных статических сайтов рассмотрите предварительно сжатые файлы. Ваш процесс сборки может создавать .gz версии больших CSS и JavaScript файлов, и Nginx может отдавать их, когда браузер поддерживает Gzip:
gzip_static on;
Это уменьшает работу по сжатию во время выполнения, потому что Nginx читает предварительно сжатый файл с диска. Это наиболее полезно, когда ресурсы собираются заранее и не меняются между запросами.
Сжатие — это только часть доставки ресурсов. Размер файла все еще имеет значение. Удалите неиспользуемый JavaScript, оптимизируйте изображения во время процесса сборки и избегайте отправки больших файлов, которые не нужны пользователям.
Когда вы тестируете сжатие, включите заголовок Accept-Encoding:
curl -I -H 'Accept-Encoding: gzip' https://example.com/assets/app.js
Ищите Content-Encoding: gzip и Vary: Accept-Encoding. Заголовок Vary важен, когда перед Nginx находится CDN или общий кэш, потому что сжатые и несжатые ответы не должны смешиваться.
Улучшите доставку файлов и безопасность
Nginx может эффективно обслуживать статические файлы с настройками по умолчанию, но несколько деталей помогут в продакшене.
Во-первых, отключите листинг каталогов, если он вам явно не нужен:
autoindex off;
Листинг каталогов может раскрыть имена файлов и структуру, которые вы не собирались публиковать.
Во-вторых, заблокируйте доступ к скрытым файлам, таким как .env, .git и другим dot-файлам:
location ~ /\.(?!well-known) {
deny all;
}
Исключение для .well-known распространено, потому что проверка сертификатов и файлы на основе стандартов могут использовать этот каталог.
В-третьих, убедитесь, что права доступа к вашим статическим файлам позволяют Nginx читать файлы, но не дают веб-серверу ненужных прав на запись. Типичная настройка позволяет инструментам развертывания записывать файлы, а пользователю рабочего процесса Nginx — читать их.
В-четвертых, проверьте MIME-типы. Nginx обычно включает файл mime.types, но урезанные контейнеры или пользовательские сборки могут его пропустить. Если CSS отдается как text/plain, браузеры могут отклонить его или вести себя иначе.
Используйте:
include /etc/nginx/mime.types;
default_type application/octet-stream;
Наконец, следите за логами на предмет повторяющихся ответов 404 на ресурсы. Это часто означает, что развертывание ссылалось на несуществующие файлы, кэш все еще указывает на старое имя файла или путь alias неверен.
Если статическая доставка кажется медленной, не начинайте с копирования каждой директивы по настройке, которую вы можете найти. Сначала проверьте, действительно ли проблема в Nginx. Большие изображения, неоптимизированные фронтенд-сборки, удаленные хранилища и промахи кэша CDN являются более распространенными причинами, чем отсутствие микрооптимизации в блоке сервера.
Для быстрой локальной проверки:
curl -o /dev/null -s -w 'status=%{http_code} size=%{size_download} time=%{time_total}\n' https://example.com/assets/app.js
Затем сравните это с логами CDN, инструментами разработчика браузера или запросом из того же региона, что и ваши пользователи. Быстрый ответ от Nginx и медленный ответ в браузере обычно указывают на другое место в пути доставки.
Когда обращаться за помощью
Привлеките DevOps-инженера, если ваши статические файлы обслуживаются из общего хранилища, смонтированных томов, шлюзов объектного хранилища или CDN перед Nginx. Лучшая стратегия кэширования зависит от всего пути доставки, а не только от блока сервера Nginx.
Вам также следует обратиться за помощью, если пользователи сообщают об устаревшем JavaScript после развертываний. Это обычно означает, что правила кэширования и стратегия версионирования имен файлов не совпадают.
Обслуживание статических файлов с Nginx работает лучше всего, когда пути предсказуемы, время жизни кэша соответствует стратегии именования файлов, а текстовые ресурсы сжаты. Держите отсутствующие файлы видимыми, защищайте скрытые файлы и тестируйте заголовки после каждого изменения конфигурации. Чистая настройка статики делает ваш сайт быстрее без добавления движущихся частей.