Вопрос или проблема
У меня есть сервер A, который принимает HTTPS-запросы, такие как:
https://example.com/CHANGEME/example/index.html
У меня есть сервер B, который принимает:
https://CHANGEME.example.com/example/index.html
Клиент должен обращаться только к серверу A.
Вопрос: как я должен настроить прокси NGINX на сервере A, чтобы использовать строку между первыми двумя “/” и использовать ее в качестве поддомена?
Важно вырезать эту часть из пути и использовать ее как поддомен.
Конечно, когда сервер A получает ответ от сервера B, поддомен должен быть переписан обратно в путь для клиента.
Все, что я пробовал, не работало, и это, кажется, нетипичная проблема.
Я упустил какую-то функцию перезаписи шаблона?
заранее спасибо!
редактировать:
Я хотел бы немного изменить мой вопрос, так как он не работает, как ожидалось.
Теперь я хотел бы реализовать обратное проксирование на основе значения cookie.
Для тестирования я установил cookie с именем url и значением CHANGEME.
В конфигурации NGINX я пробовал:
location / {
resolver 8.8.8.8;
proxy_pass https://$cookie_url.example.com;
}
Который в целом работает и загружает нужный сайт.
Проблема в том, что клиент также пытается подключиться к mqtt брокеру wss://example.com/mqtt, и это приводит к ошибке.
Я думаю, из-за отсутствия опции чтения cookie?
Есть шанс, что это будет работать?
Это должно работать следующим образом:
server {
location ~ ^/(?<subdomain>[^/]+)(?<path>.*)$ {
proxy_pass http://$subdomain.example.com$path;
}
}
Блок location
соответствует путям и захватывает строку между первыми двумя косыми чертами в переменную $subdomain
. Затем остальная часть пути захватывается в переменную $path
. Полученные значения затем используются в качестве назначение proxy_pass
.
Я могу ответить на вопрос сам.
Получилось.
Недостающая часть конфигурации в location была:
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
Ответ или решение
Для решения вашей задачи с перенаправлением и проксированием запросов в NGINX в зависимости от части пути, которую необходимо использовать в качестве поддомена, нужно использовать грамотную конфигурацию NGINX. Вы описали сценарий, в котором требуется:
- Поступающие запросы на сервер A имеют вид:
https://example.com/CHANGEME/example/index.html
. - Вам нужно перенаправить их на сервер B в форме:
https://CHANGEME.example.com/example/index.html
. - При обратном ответе от сервера B, нужно восстановить исходный формат URL, чтобы клиент получал те же URL, что и запрашивал, находясь на сервере A.
Теоретическая часть
Для решения вашей задачи, NGINX предлагает мощный инструмент регулярных выражений и переменных, которые можно использовать в блоках location
, чтобы извлекать части из URL и применять их в дальнейших конфигурациях, таких как proxy_pass
.
- Блок location: Использование регулярных выражений в конфигурации location позволяет извлекать части URL и сохранять их в переменных.
- Переменные NGINX: Позволяют динамически формировать конечный URL-запрос для проксирования.
- Proxy_pass: Директива, позволяющая перенаправить запросы к другому серверу, может использовать динамически определенные переменные.
Пример
Используя предложенные вами методы и дополнительную логику, мы можем создать следующую конфигурацию:
server {
listen 80;
server_name example.com;
location ~ ^/(?<subdomain>[^/]+)(?<path>/.*)$ {
# Извлечь поддомен и путь из URL
proxy_pass http://$subdomain.example.com$path;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# Дополнительно можно настроить заголовки, чтобы сохранить сессию и куки
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
Объяснение:
- Переменная
<subdomain>
извлекается из URL и используется для построения проксированного URL. - Переменная
<path>
сохраняет остальную часть пути для проксирования. - Директива
proxy_set_header
используется для переноса определенных заголовков, которые необходимы для правильной обработки запроса на сервере B.
Практическое применение
Ваш сценарий затрудняется ещё и необходимостью работы с MQTT по websocket-соединению. Ваша конфигурация указала на использование cookie для этих целей:
location / {
resolver 8.8.8.8;
proxy_pass https://$cookie_url.example.com;
}
Однако для работает ли прямое использование cookies в имени сервера, нужно учитывать, что NGINX не имеет прямого функционала для одновременного использования cookie как серверного адреса и поддержки websocket без необходимых заголовков. Как вы правильно заметили, при работе с websocket необходимы заголовки Upgrade
и Connection
.
Добавление :
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
позволило вам разрешить проблему с вебсокетами, но ошибки могут происходить из-за того, что не все пути (например, /mqtt
) должны использовать cookie-адресацию.
Чтобы исправить этот момент, следует:
- Обработать проксирование
/mqtt
отдельно, без использования переменной$cookie_url
, если она не нужна для MQTT. - Убедиться, что все используемые пути подготовлены для работы с cookie, и, если cookie причастен к указанию нужного сервера, быть уверенным в его наличии.
Вывод
Настройка NGINX требует внимания к деталям, особенно при работе с динамичными поддоменами и специфическими протоколами, такими как websocket. Регулярные выражения и переменные NGINX способны значительно упростить подобные задачи, если правильно воспользоваться ими в конфигурациях. Вполне возможно, потребуется дополнительная обработка куки и/или использование дополнительных блоков конфигурации для различных услуг, как в вашем случае с MQTT, чтобы обеспечить корректное выполнение всех функций прокси-сервера.
Если у вас остаются проблемы с подключением к mqtt-брокеру, вам, возможно, следует также рассмотреть альтернативные подходы, такие как использование маршрутов исключения или использования других заголовков и настроек для специфичных путей в вашей конфигурации NGINX.