Перейти к содержанию
Innovialabs

Настройка Nginx для статических сайтов и SPA

Практика3 мин

Коротко

Для SPA в Nginx достаточно указать root с собранными файлами и try_files $uri $uri/ /index.html, а хешированным ассетам отдать долгий кеш, при этом index.html не кешировать.

Короткий ответ

Статический сайт или SPA (React, Vue, Angular, Svelte) после сборки — это папка с index.html, JS, CSS и картинками. Nginx отдаёт их напрямую с диска, без backend. Для SPA нужна одна важная деталь: fallback на index.html, чтобы прямые ссылки вида /profile/settings не возвращали 404.

Базовый server-блок для SPA

server {
    listen 80;
    server_name app.example.com;

    root /var/www/app/dist;
    index index.html;

    location / {
        try_files $uri $uri/ /index.html;
    }
}

try_files проверяет варианты по порядку: существует ли файл, существует ли папка, и если ничего не найдено — отдаёт /index.html. Дальше маршрут обрабатывает роутер приложения в браузере.

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

Сборщики (Vite, webpack и другие) добавляют в имена файлов хеш содержимого: app.3f9a1c.js. Если файл изменится, изменится и имя. Значит, такие файлы можно кешировать надолго, а index.html — нет, иначе пользователи не увидят новую версию.

server {
    listen 80;
    server_name app.example.com;
    root /var/www/app/dist;
    index index.html;

    location / {
        try_files $uri $uri/ /index.html;
    }

    location /assets/ {
        try_files $uri =404;
        add_header Cache-Control "public, max-age=31536000, immutable";
    }

    location = /index.html {
        add_header Cache-Control "no-cache";
    }
}
Тип файлаПолитика кеша
Хешированные JS, CSS, шрифтыДолгий кеш, immutable
index.htmlno-cache — браузер перепроверяет каждый раз
Картинки без хеша в имениУмеренный кеш или хеш в имени

Обратите внимание на try_files $uri =404 в /assets/: отсутствующий JS-файл должен давать честную 404, а не index.html с кодом 200. Иначе браузер получит HTML вместо скрипта и выдаст непонятную ошибку.

Путь /assets/ зависит от сборщика — проверьте, куда он кладёт файлы.

Многостраничный статический сайт

Для сайта, где каждая страница — отдельный HTML-файл (генераторы статики, лендинги), fallback на index.html не нужен. Вместо него — поддержка адресов без расширения и своя страница 404:

server {
    listen 80;
    server_name example.com;
    root /var/www/site;
    index index.html;

    location / {
        try_files $uri $uri.html $uri/ =404;
    }

    error_page 404 /404.html;
}

Несколько сайтов на одном сервере

Nginx выбирает блок по заголовку Host и директиве server_name. Каждому сайту — свой файл:

  • /etc/nginx/sites-available/app.example.com со ссылкой в sites-enabled, или
  • /etc/nginx/conf.d/app.example.com.conf — в зависимости от дистрибутива.

Каждый файл содержит свой server с собственными server_name и root. Чтобы запросы на неизвестные домены не попадали на случайный сайт, задайте отдельный блок с listen 80 default_server; и return 444;.

Частые ошибки

  • Нет fallback для SPA. Главная работает, а обновление страницы на /dashboard даёт 404.
  • Долгий кеш на index.html. После деплоя пользователи видят старую версию, пока не почистят кеш.
  • Потерянные заголовки. add_header внутри location отменяет все add_header уровня server. Если на уровне server заданы заголовки безопасности, повторите их в location или вынесите в общий include.
  • Неверные права. Пользователь, под которым работает Nginx, должен иметь доступ на чтение к папке сайта.
  • Применение без проверки. Всегда запускайте nginx -t перед systemctl reload nginx.

Частые вопросы

Браузер запрашивает у сервера путь вроде /orders/42, а такого файла на диске нет. try_files $uri $uri/ /index.html отдаёт index.html, и маршрут обрабатывает роутер приложения.

Поможем с этим

Если хотите не разбираться самим, а получить результат — этим мы занимаемся каждый день.

Обсудить проект

Читайте также

Есть идея или задача? Расскажите нам

Ответим в течение рабочего дня и предложим решение. Консультация бесплатная.