Как стать автором
Обновить

Nginx и Websockets

Nginx *
В Nginx наконец добавили долгожданную функциональность по проксированию Websockets.
В связи с этим спешу поделиться конфигами и небольшими подробностями.

Для тех кто не знал, ранее проксирование было возможно через сторонний модуль, с ограничениями которые многих не устраивали. Ну, да мы не об этом.


Теперь на одном порту можно проксировать http и ws траффик, более того, например под одним SSL сертификатом, и все это с родным знакомым синтаксисом.

Ws доступны начиная с версии 1.3.13, а буквально сегодня добавили поддержку еще в модули ngx_http_uwsgi_module и ngx_http_scgi_module для 1.3.14

Вот, что говорит документация на счет используемого механизма.


Для превращения соединения между клиентом и сервером из HTTP/1.1 в WebSocket используется доступный в HTTP/1.1 механизм смены протокола.

Но есть сложность: поскольку “Upgrade” является hop-by-hop заголовком, то он не передаётся от клиента к проксируемому серверу. При прямом проксировании клиенты могут использовать метод CONNECT, чтобы обойти эту проблему. Однако при обратном проксировании такой подход не работает, так как клиент ничего о проксирующем сервере не знает, и требуется специальная обработка на проксирующем сервере.

Начиная с версии 1.3.13, в nginx предусмотрен особый режим работы, который позволяет установить туннель между клиентом и проксируемым сервером, если проксируемый сервер вернул ответ с кодом 101 (Switching Protocols), и клиент попросил сменить протокол с помощью заголовка “Upgrade” в запросе.

Как уже отмечалось выше, hop-by-hop заголовки, включая “Upgrade” и “Connection”, не передаются от клиента к проксируемому серверу, поэтому, для того чтобы проксируемый сервер узнал о намерении клиента сменить протокол на WebSocket, эти заголовки следует передать явно:

Конфиг.


Простой пример:

location /ws/ {
    proxy_pass http://localhost:8080;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";

}


Более сложный пример, в котором значение поля “Connection” в заголовке запроса к проксируемому серверу зависит от наличия поля “Upgrade” в заголовке запроса клиента:

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

    server {
        ...

        location /ws/ {
            proxy_pass http://localhost:8080;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;
        }
    }


И немного неочевидный, но важный параметр это proxy_read_timeout, который стоит по дефолту в значении 60s, по истечении которых коннект обрывается, чего в случае ws обычно совсем не нужно.

Поэтому, мы добавили:

http {
      ...
      proxy_read_timeout 950s;
      ...
}


Скорее всего вашему приложению нужны будут другие цифры таймаута, поэтому не копипастите бездумно;)
Теги:
Хабы:
Всего голосов 93: ↑90 и ↓3 +87
Просмотры 94K
Комментарии Комментарии 12