Магия Nginx и React Router: Как заставить SPA работать правильно

Магия Nginx и React Router: Как заставить SPA работать правильно

Вы создали красивое React-приложение с клиентской маршрутизацией, собрали его в аккуратный бандл и загрузили на сервер. Но при обновлении страницы или прямом переходе по URL вместо вашего приложения появляется холодная ошибка 404. Знакомая ситуация? Это классическая проблема SPA с React Router, и решается она правильной настройкой веб-сервера. В этой статье мы разберем, как настроить Nginx для безупречной работы вашего React-приложения.

Почему React Router ломается на сервере?

React Router — это клиентский маршрутизатор. Когда пользователь заходит на главную страницу (/), сервер отдает index.html, React загружается, и Router берет управление на себя. Все переходы происходят без перезагрузки страницы. Но если пользователь обновит страницу на /about или перейдет по прямой ссылке, Nginx попытается найти файл /about/index.html (или просто about) в папке с билдом. Его там нет — отсюда и 404.

Ключевой принцип: при любом запросе (кроме запросов к статическим файлам) сервер должен возвращать один и тот же index.html. React Router сам разберется с URL и отрендерит нужный компонент.

Базовая конфигурация Nginx

Стандартная конфигурация для статики не подходит. Вот минимальный рабочий конфиг для сайта:

Основной server блок

server {
    listen 80;
    server_name yourdomain.com;
    root /var/www/your-react-app/build;
    index index.html;

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

    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
        expires 1y;
        add_header Cache-Control \"public, immutable\";
    }
}

Директива try_files $uri $uri/ /index.html; — это сердце настройки. Nginx пытается найти запрошенный файл или папку, и если не находит — отдает index.html.

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

Работа с API-проксированием

Часто фронтенд обращается к бэкенду на другом порту. Настроим проксирование:

location /api/ {
    proxy_pass http://localhost:3000/;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;
}

Важно! Располагайте блок location /api/ выше блока location /. Nginx выбирает location по наиболее специфичному совпадению.

Поддержка HTML5 History API и хэш-роутинга

Если вы используете старый HashRouter (с # в URL), конфигурация проще — проблемы с 404 не возникает. Но для современного BrowserRouter (History API) наша настройка обязательна.

Настройка кэширования и gzip

Добавьте сжатие для ускорения загрузки:

gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;

Решение частых проблем

  • Белый экран после деплоя: Проверьте, что root ведет на папку build, и в ней есть index.html. Проверьте права доступа (часто chmod -R 755 /var/www/your-app).
  • Статические файлы не грузятся: Убедитесь, что блок для статики корректно настроен и файлы существуют.
  • Ошибки 404 для API-запросов: Проверьте путь проксирования и работает ли бэкенд-сервер.

Проверка и перезагрузка конфигурации

  1. Проверьте синтаксис: sudo nginx -t
  2. Если ок — перезагрузите: sudo systemctl reload nginx или sudo nginx -s reload
  3. Очистите кэш браузера при тестировании!

FAQ: Часто задаваемые вопросы

Нужно ли это для Create React App?

Да, если вы используете React Router и выкладываете билд на свой сервер. На хостингах вроде Vercel или Netlify это настраивается автоматически.

А как насчет Apache?

Для Apache нужен файл .htaccess с правилом RewriteRule, которое также перенаправляет все запросы на index.html.

Что делать с 404 ошибками для несуществующих путей?

React Router должен сам отображать компонент "Страница не найдена" (404). Сервер всегда отдает index.html, а роутинг на стороне клиента определяет, что такого маршрута нет.

Можно ли использовать с Docker?

Конечно. Поместите конфиг Nginx в контейнер и скопируйте в него папку build. Или используйте готовый образ, например, nginx:alpine.