Рейтинг:0

Двойной прокси-сервер NGINX не разрешает подключения через веб-сокет

флаг lb

У меня на компьютере установлено два прокси-сервера nginx: один для развертывания SSL, а другой для проксирования для конкретного приложения (только второй контролируется версией). Когда у меня был только один прокси-сервер, я мог успешно подключаться к веб-сокетам, но после перехода на два все запросы на обновление веб-сокетов отвечают ошибкой 502 Bad Gateway. Я могу подтвердить, что обычные запросы http/https работают с моей настройкой двойного прокси. Вот мой текущий конфиг.

Прокси 1

сервер {

        # конфигурация SSL
        #
        # слушать 443 ssl default_server;
        # слушать [::]:443 ssl default_server;
        #
        # Примечание. Вы должны отключить gzip для трафика SSL.
        # См.: https://bugs.debian.org/773332
        #
        # Прочтите ssl_ciphers, чтобы обеспечить безопасную конфигурацию.
        # См.: https://bugs.debian.org/765782
        #
        # Самоподписанные сертификаты, созданные пакетом ssl-cert
        # Не используйте их на рабочем сервере!
        #
        # включить фрагменты/snakeoil.conf;

        имя_сервера staging.ambitx.io;

        место расположения / {
                прокси_пасс http://127.0.0.1:81;
                включить proxy_params;
        }

    слушать [::]:443 ssl ipv6only=on; # под управлением Certbot
    слушать 443 ssl; # под управлением Certbot
    ssl_certificate /etc/letsencrypt/live/staging.ambitx.io/fullchain.pem; # под управлением Certbot
    ssl_certificate_key /etc/letsencrypt/live/staging.ambitx.io/privkey.pem; # под управлением Certbot
    включить /etc/letsencrypt/options-ssl-nginx.conf; # под управлением Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # под управлением Certbot

}
сервер {
    если ($ host = staging.ambitx.io) {
        вернуть 301 https://$host$request_uri;
    } # управляется Certbot

        слушать 80 default_server;
        слушать [::]:80 default_server;

        имя_сервера staging.ambitx.io;
    вернуть 404; # под управлением Certbot

}

proxy_params

proxy_set_header Хост $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $ схема;

Прокси 2

(работает на докере с портом 81 на хост-компьютере, привязанным к порту 80 в контейнере)

резолвер 127.0.0.11 ipv6=выкл.;

сервер {
  слушать 80;
  слушать [::]:80;

  место расположения / {
    корень /var/www/staticfiles;
    индекс index.html index.htm;
    try_files $uri /index.html =404;
  }
  
  местоположение / ws {
    доступ_лог выключен;

    прокси_пароль http://wsserver;

    прокси_http_версия 1.1;
    proxy_set_header Обновить $http_upgrade;
    proxy_set_header Соединение "обновление";
  }

  расположение /API {
    прокси_пасс http://apserver;
  }
}

Первоначально у меня были утверждения ниже в местоположение /ws блок конфигурации Proxy 2...

proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Хост $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

но я удалил их, потому что они будут перезаписывать заголовки, установленные прокси-сервером 1.

Любые идеи? Пожалуйста, дайте мне знать, если вам нужна дополнительная информация.

Рейтинг:0
флаг gr

Конечно, вы не должны отказываться от поддержки проксирования WebSocket ни с одного из ваших промежуточных прокси-серверов. Проксирование WebSocket очень специальное задание, чтобы разрешить переключение протоколов и поддерживать установленное и активное соединение WebSocket, вы также должны вернуть его поддержку вашему первому прокси-серверу nginx:

...
место расположения / {
    прокси_пасс http://127.0.0.1:81;
    включить proxy_params;
}
местоположение / ws {
    прокси_пасс http://127.0.0.1:81;
    включить proxy_params;
    прокси_http_версия 1.1;
    proxy_set_header Обновить $http_upgrade;
    proxy_set_header Соединение "обновление";
}
...

Удаление всех трех proxy_set_header директивы от вашего второго прокси-сервера nginx также были плохой идеей. Пока X-Real-IP и X-переадресовано-для заголовки будут переданы вашему приложению WebSocket точно так же, как они установлены вашим первым прокси-сервером, Хозяин заголовок особенный. Если не задано явно, оно будет передано равным имени восходящего потока, используемому в proxy_pass директива, т.е. Хост: wsserver. Как вы можете прочитать из proxy_set_header директива документация:

По умолчанию переопределяются только два поля:

proxy_set_header Хост $proxy_host;
proxy_set_header Соединение закрыто;

(второй наверняка сломает любую попытку установить соединение WebSocket). Итак, чтобы сохранить оригинал Хозяин заголовок из клиентского запроса (обычно хорошая идея, вы можете прочитать больше об этом заголовке здесь), вернуть

хост proxy_pass $http_host;

линия к обоим место расположения / { ... } и местоположение /ws { ... } вашей второй конфигурации прокси-сервера nginx.

Simon Richard avatar
флаг lb
Это сработало для меня, спасибо. Чтобы прокси-сервер 1 не зависел от прокси-сервера 2 (поскольку прокси-сервер 1 в настоящее время не контролируется версиями), я решил использовать «более сложный пример» (второй), указанный на этом веб-сайте: https://nginx.org /en/docs/http/websocket.html вместо этого и просто добавьте его в блок `location / { ... }` в прокси 1. Таким образом, если я изменю URL-адрес веб-сокета, но забуду о прокси 1, он не сломается. Единственным недостатком этого, о котором я могу думать, является то, что он не сможет обрабатывать http/2.0, но мой сервер все равно не был настроен для его обработки.
Ivan Shatsky avatar
флаг gr
Это звучит разумно, я тоже предпочитаю такой способ проксирования WebSocket. Что касается HTTP/2, вы можете найти [эту] (https://serverfault.com/questions/765258/use-http-2-0-between-nginx-reverse-proxy-and-backend-webserver) ветку довольно интересной.

Ответить или комментировать

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