На самом деле всё очень просто (для тех кто с 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 решение:
- Подключаемся к серверу
- sudo vi /etc/nginx/sites-available/default
- Тыкаем клавишу " i "
- Находим и удаляем строку: try_files $uri $uri/ =404;
- На её место вставляем это: try_files $uri $uri/ /index.html;
- Тыкаем клавишу esc
- Пишем: :wq и Enter - тем самым сохраняем и выходим из редактора
- sudo systemctl restart nginx
- done!