Nginx proxy-pass несколько переписей с подключением по WebSocket

Вопрос или проблема

Я наткнулся на проблему конфигурации, которую считал относительно легкой для решения. К сожалению, это, похоже, не так.

Вот в чем проблема: я хотел бы использовать несколько docker экземпляров Jupyter notebooks для обслуживания проекта документации, состоящего из нескольких документов (использование JupyterHub не рассматривается в данный момент). Каждый docker экземпляр был бы подключен к «внешнему» docker мосту, чтобы каждый экземпляр был доступен через его DNS имя. Но для простоты я сначала начинаю здесь с доступа к одному экземпляру через его отображаемый порт на 127.0.0.1:8888. Я хотел бы, чтобы опубликованный документ (скомпилированный с помощью dockerized Sphinx, также встроенного в контейнер) появился, например, под https://exemple.com/document1, а его «редактируемая» версия была доступна под https://exemple.com/document1/edit.

Вот моя конфигурация Nginx (только релевантные части):

upstream jupyter {
 server 127.0.0.1:8888;
}

map $http_upgrade $connection_upgrade {
 default upgrade;
 '' close;
}

server {
    listen 80;

    server_name exemple.com 

    include snippets/letsencrypt.conf;

    if ($request_uri !~ ^/\.well-known) {
        rewrite ^(.*) https://$host$1 permanent;
    }    
}

server {

    # server port and name
    listen 443 ssl http2;
    server_name exemple.com;

    # Let's Encrypt SSL
    ....

   if ($request_uri ~* ^(.*)\/edit) {
            rewrite ^(.*)$ /edit/$1;
   }

    location /  {
        alias /var/www/document1/_build/html/;
        index index.html index.htm;
   }

   location /edit/ {
       # Proxy
       rewrite ^(.*)\/edit\/(.*)$ $1/$2 break;
       proxy_pass http://jupyter;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            # WebSocket support
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;
    }
}

Я думал, что расположение “/edit/” должно иметь приоритет над “/edit” и, следовательно, передавать запросы на сервис docker 127.0.0.1:8888. URL https://exemple.com/document1 обслуживается правильно, но при переходе на https://exemple.com/document1/edit я вижу, что веб-запросы обслуживаются правильно, но кажется, что websocket соединение закрывается, как только активируется.
См. журнал сети Chrome
Что я упускаю здесь?
Заранее большое спасибо за любые подсказки 😉

Ответ или решение

Конфигурация Nginx, используемая для проксирования запросов и веб-сокетов к докеру Jupyter, может вызвать затруднения, особенно при настройке нескольких переписываний URL и подключении веб-сокетов. Рассмотрим проблему более подробно.

Теория

Nginx часто используется в качестве обратного прокси-сервера для управления входящими запросами и распределения их к соответствующим сервисам, которые могут работать в отдельных контейнерах Docker. Он также может выступать в качестве SSL-терминатора, обеспечивая шифрование на уровне транспортного слоя. В данной конфигурации основной задачей является обеспечение доступности документов, генерируемых с использованием Sphinx и Jupyter, а также правильная маршрутизация запросов, включая поддержку веб-сокетов для редактирования.

Пример

В вашем случае, конфигурация Nginx состоит из двух серверных блоков для обработки HTTP и HTTPS запросов. Особое внимание уделяется следующему:

  • Переписывание запросов: Используется для направления запросов с /edit на соответствующий проксирующий сервер.
  • Поддержка веб-сокетов: Настройки веб-сокетов, такие как proxy_set_header Upgrade и proxy_set_header Connection, необходимы, чтобы уведомить сервер о том, что соединение должно быть "повышено" до веб-сокета.

Проблема

Ваше описание проблемы включает в себя корректное отображение страниц по адресу https://exemple.com/document1, но сбой подключения веб-сокетов при доступе к https://exemple.com/document1/edit. Это указывает на вероятные проблемы с переработкой URI и маршрутизацией веб-сокетов.

Кроме того, ваш код содержит некоторые потенциальные ошибки:

  1. Включение блоков if может вызывать неожиданные эффекты при работе со сложными конфигурациями. В контексте Nginx if может иногда приводить к неожиданному поведению, особенно когда конфигурация сети должна учитывать веб-сокеты.

  2. Переписывания в блоке location, особенно с условием break, могут вызывать конфликт с обработкой заголовков веб-сокетов. Веб-сокеты требуют устойчивого соединения, и здесь важно убедиться, что заголовки обработаны правильно.

  3. SSL-настройки и их отсутствие в предоставленном коде. Без полной конфигурации SSL возможно, что какие-то заголовки или параметры запроса могут быть потеряны.

Решение

Теперь давайте рассмотрим, как можно решить данную проблему:

  1. Проверка переписывания URL: Проверьте порядок переписывания и убедитесь, что маршрутизация определяется правильно. Также избегайте использования условных операций, которые могут привести к неожиданным последствиям в контексте Nginx.

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

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

  4. Проверка Docker-сети: Проверяйте, что докер-контейнеры правильно настроены для взаимодействия с хост-сетью и имеют доступ к необходимым для работы порту и DNS-именам.

Пример доработанной конфигурации

upstream jupyter {
    server 127.0.0.1:8888;
}

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

server {
    listen 80;
    server_name exemple.com;

    include snippets/letsencrypt.conf;

    location / {
        return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl http2;
    server_name exemple.com;

    # Добавьте ваши SSL конфигурации

    location /document1 {
        alias /var/www/document1/_build/html/;
        index index.html index.htm;
    }

    location /document1/edit {
        proxy_pass http://jupyter;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
    }
}

Заключение

Корректная настройка Nginx с поддержкой веб-сокетов может быть непростой задачей в среде с несколькими сервисами и переписываниями URL. При этом важно тщательно проверить конфигурацию и использовать отладочные средства, чтобы выявить и корректировать проблемы на ранних стадиях настройки системы.

Оцените материал
Добавить комментарий

Капча загружается...