Настройка nginx для статики

Конфигурируем nginx для статического сайта или блога


Настройка vhost и отдача статики

Один nginx может обслуживать несколько виртуальных хостов (vhost), различая их по заголовку Host в запросе. При запросе из браузера доменное имя, такое как example.com, автоматически попадает в заголовок Host.

Пример:

server {
    listen 8080;
    listen [::]:8080;

    server_name example.com example.local localhost;

    root /app/public;

    location / {
        index index.html;
    }
}

Пояснения к примеру:

Кеширование статики

Пример:

server {
    # Другие директивы

    location ~* \.(svg|png|webp|jpg|jpeg|gif|ico) {
        expires 30d;
    }

    location ~* \.(css|js|woff|woff2|webmanifest) {
        expires 180d;
    }
}

Пояснения к примеру:

  1. Директива expires 30d; установит заголовки, чтобы браузер хранил статику 30 дней, например
    • Cache-Control: max-age=2592000
    • Expires: Sun, 11 Mar 2025 13:26:14 GMT (+30 дней от 9 февраля 2025)
  2. Кеширование включено для типовой статики:
    • изображений в форматах SVG/PNG/WEBP/JPEG/GIF/ICO — на 30 дней
    • стилей CSS, скриптов JS, шрифтов в форматах WOFF/WOFF2, файла Web App Manifest — на 180 дней
  3. Хранить можно и дольше — но не забывайте:
    • сайт меняется и его статика тоже
    • кеш клиента не безграничен и может очищаться от старых файлов

Версионирование статики

Если кеширование есть, а версионирования статики нет, то при обновлении сайта у клиента могут «поехать» стили и сломаться JavaScript.

Версионирование статики можно вести:

  1. Автоматически — средствами генератора статического сайта
  2. Вручную — силами разработчика сайта

Популярные методы версионирования:

Сжатие gzip

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

Пример:

server {
    # ... другие директивы

    gzip on;
    gzip_types text/html text/css application/javascript image/svg+xml text/xml application/xml+rss;
    gzip_proxied no-cache no-store private expired auth;
    gzip_comp_level 6;
}

Пояснения к примеру:

  1. В примере включено GZIP сжатие «на лету» для HTML, CSS, JS, SVG файлов, а также для XML (например, sitemap) и XML+RSS (для RSS ленты)
  2. Директива gzip_proxied включает сжатие для клиентов, использующих proxy сервер
    • proxy часто включены в офисных компьютерах различных организаций
  3. Уровень сжатия установлен на 6

Если всё настроено верно, то в браузере в DevTools вы сможете увидеть заголовок ответа Content-Encoding: gzip.

Для каких MIME типов включать GZIP?

Стоит сжимать все текстовые форматы: HTML, CSS, JS, SVG. Минифицированные файлы CSS/JS тоже стоит сжимать.

Нет смысла включать GZIP сжатие:

  1. Для изображений PNG, JPEG, WEBP, GIF, потому что сжатие заложено в алгоритмы кодирования изображений
    • тем не менее, можно сжать сами изображения лучше — подробности ищите по запросам «png optimizer», «jpeg optimizer»
  2. Для web шрифтов в формате WOFF и WOFF2 — в них заложено сжатие алгоритмами deflate и brotli соответственно
  3. Для видео и аудио в типовых форматах: OGG, MP3, MP4 и так далее — сжатие заложено в алгоритмы кодирования видео/аудио

Посмотреть доступные для nginx MIME типы в Linux можно командой:

cat /etc/nginx/mime.types

Использование gzip_static

Иногда при создании сайта есть возможность заранее сжимать файлы в GZIP.

Допустим, генератор статического сайта сжимает файлы HTML/JS/CSS в GZIP архивы:

Тогда в nginx можно задействовать директиву gzip_static с тремя вариантами:

Пример:

server {
    # ... другие директивы

    # Отдавать сжатый контент из файла *.gz, если он найден
    gzip_static on;

С такой конфигурацией nginx будет: