Nginx и Websockets

от автора

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

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

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

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

Для описания механизма ws в Nginx оставлю здесь цитату Максима Дунина.

Short version:

Устанавливает тоннель между клиентом и бекендом.

Long version, чтобы два раза не вставать:

Вообще протокол WebSocket работает с помощью механизма Upgrade,
присутствующего в HTTP/1.1, превращая соединение между клиентом и
сервером из HTTP/1.1 в WebSocket.

Есть, однако, нюанс: этот hop-by-hop механизм, он в нормальных
условиях не может проходить через proxy-сервера. Для forward
proxy в стандарте WebSocket есть затычка: клиентам предлагается
использовать CONNECT, чтобы пройти через proxy-сервер без потерь
(тот же CONNECT используется для того, чтобы через forward proxy
можно было ходить на https-ресурсы). Но с reverse proxy такой
подход не работает, т.к. клиент о proxy вообще не знает, и
требуется специальная обработка.

В вышеупомянтом коммите — добавлен специальный режим работы,
который позволяет nginx’у установить тунель между клиентом и
бекендом, если бекенд прислал ответ 101 Switching Protocols (и
если клиент действительно хотел upgrade’ить соединение).

Следует иметь ввиду, что по умолчанию nginx убирает из запроса на
бекенд hop-by-hop заголовки Upgrade и Connection, так что для
того, чтобы бекенд узнал, что клиент хотел upgrade’ить соединение,
эти заголовки надо явно пробросить.

Конфиг.

Простой пример, как теперь можно заставить работать ws:

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;       ... }  

Скорее всего вашему приложению нужны будут другие цифры таймаута, поэтому не копипастите бездумно;)

ссылка на оригинал статьи http://habrahabr.ru/post/171757/


Комментарии

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *