На самом деле всё очень просто (для тех кто с Nginx на «Вы» в конце поста я вставил комментарий от Евгения Лобашёва) и я очень удивлён почему соответсвующий запрос в поисковике очень мало ответов на русском языке.

Ответ прост как три копейки:

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


Обновление от 24.09.2019:


Сделал что-то новое? Получил новые знания? Пиши! Это кажется тебе незначительным? Пофиг! Всё равно пиши! Для этого даже специальный хештег придумали #TIL — Today I Learned — сегодня я узнал. Во-первых это закрепит эти знания в твоей голове, а во-вторых обязательно кому-то поможет. Верьте мне, эта короткая заметка одна из самых популярных на моём сайте.

На этом лирическо–мотивационное вступление окончено.


Проблема

Так исторически сложилось, что разные инстансы (продакшн и стейдж) одних и те же приложения на моём компьютере висели на разных портах на одном домене. Т.е., вот так prod на localhost:9050, и стейдж на localhost:9080 и у этой схемы нет серьёзных недостатков пока не возникает необходимости сравнить поведение приложения в разных условиях. Например, из-за обновления API. И вот тут возникает проблема, которая не сказать, что серьёзная, но раздражающая: все мои приложения требуют регистрации и оная запоминается древним как говно мамонта способом — с помощью установки кук. Куки, как многие из вас знают из параграфа 8.5 волшебного документа RFC 6265, не изолируются по порту, и ставятся целиком на домен.


В моём случае это значило только одно: либо открывай разные браузеры и заходи в них в разные инстансы, либо открывай ещё одно окно в приватном режиме. Вариант «открыть в соседней вкладке» здесь, как видите, не предусмотрен. Не удобненько.



Сегодня я решил это исправить и, надо сразу сказать, что я не великий гуру настройки NGINX. Совсем даже наоборот.


Конфигурация NGINX

Начну с результата, но сначала сделаю небольшое отступление и расскажу, что из себя представляют проекты с которыми я работаю. Есть основная Админка и есть Статистика по проектам наших пользователей. Это два разных приложения. Админка это легаси монстр с питонячьим сервером WSGI под капотом, который в конечном счёте раздаёт статику. Статистика это стильное модное молодёжное SPA приложение написанное мной на Typescript, с помощью React, Mobx и всё того же React router. Пользователи сначала заходят в Админку и там в главном меню могут перейти в Статистику.


Вот именно в разруливании этого роутинга и состояла моя задача.


#PRODUCTION
server {
  server_name admin.crm;

  location / {
    proxy_pass http://localhost:8090/;
  }

  location ~ /stat/(.*) {
    alias /Users/inoy/projects/statistics/build/;
    try_files $1 $1/ /stat/index.html; #здесь вместо $1 наверняка сработает и $uri, но я не пробовал
  }

  location ~ /system/status(.*)$ {
    alias /Users/inoy/projects/statistics/build/;
    try_files $1 $1/ /stat/index.html;
  }

  location /api/ {
    proxy_pass https://url.of.api.endpoint.ru/api/;
    proxy_read_timeout 300s;
  }

  location /uploader/ {
    proxy_pass https://url.of.api.endpoint.ru/uploader/;
    proxy_read_timeout 300s;
  }
}

А теперь о том, что здесь происходит.


server_name — директива которая матчит запрошенный домен с соответствующим блоком server {} в конфиге NGINX. Естественно, в файле hosts стоит соответствующая строчка: 127.0.0.1 admin.crm.


location / {
  proxy_pass http://localhost:8090/;
}

— проксирование запроса к серверу WSGI который, как видно, тоже запущен на локальной машине.


location ~ /stat/(.*) {
  alias /Users/inoy/projects/statistics/build/;
  try_files $1 $1/ /stat/index.html;
}

— обработка запросов к Статистике с учётом того, что это SPA приложение и обновление страницы должно нас приводить туда же, а не на 404 страницу.


location ~ /system/status(.*)$ {
  alias /Users/inoy/projects/statistics/build/;
  try_files $1 $1/ /stat/index.html;
}

— обработка запросов к секретной странице мониторинга (ага–ага, чистой воды security through obscurity). Всё тоже самое, ничего нового.


location /api/ {
  proxy_pass https://url.of.api.endpoint.ru/api/;
  proxy_read_timeout 300s;
}

— проксирование запросов к API. Вы же не разворачиваете у себя на локальной машине инстанс бекенда только для того, чтобы на фронте поправить ссылку, нет?


Вот и всё разве, что сделаю акцент на небольшом нюансе:

Почему ~ /stat/(.*) , а не просто /stat/ ? А хз. Если прописать второй вариант, то NGINX выдавал мне 500-ю ошибку. Если кто-нибудь объяснит мне почему тому я буду очень благодарен и добавлю его объяснения в этот пост. Наверное потому, что NGINX прекращает дальнейший поиск совпадений для location-ов c тильдой (регуляркой то-бишь). Без регулярки, судя по error логам, сервер зацикливается в попытках сделать запрос к /, /stat/ и index.html по кругу (за очерёдность не ручаюсь).


Постскриптум

Эта строчка в конфиге ваш лучший друг, брат, мать и Господь в одном лице. access_log становится не нужен.

error_log /var/log/nginx/error.log debug;


Для тех кто с Nginx на «Вы»


Для тех кто каждый день не занимается настройкой Nginx для React решение:

  1. Подключаемся к серверу
  2. sudo vi /etc/nginx/sites-available/default
  3. Тыкаем клавишу " i "
  4. Находим и удаляем строку: try_files $uri $uri/ =404;
  5. На её место вставляем это: try_files $uri $uri/ /index.html;
  6. Тыкаем клавишу esc
  7. Пишем: :wq и Enter - тем самым сохраняем и выходим из редактора
  8. sudo systemctl restart nginx
  9. done!