Proxying websocket (to e.g. tomcat)

Hello all!

I’ve installed the latest version 1.3.13 (supposedly supporing
websocket) and was trying to push websocket connections through nginx to
tomcat while leaving all other (static) content to nginx. To do this,
I’ve added the following “location” for tomcat:

location /examples/websocket {
proxy_pass http://127.0.0.1:8080/examples/websocket;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}

I know that tomcat itself accepts some test websocket connection just
fine. Also, getting static pages from tomcat through nginx works well
too. However, proxying websocket doesn’t seem to work.

So I’ve stopped tomcat and used netcat to see what gets through. Here it
goes:

Direct request (firefox → tomcat):

GET /examples/websocket/echoStream HTTP/1.1
Host: 192.168.0.91:8080
User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:17.0) Gecko/20100101
Firefox/17.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive, Upgrade
Sec-WebSocket-Version: 13
Origin: http://192.168.0.91:8080
Sec-WebSocket-Key: ZffbHEsoryDw1gcX51lt8g==
Pragma: no-cache
Cache-Control: no-cache
Upgrade: websocket

Request passed though nginx (firefox → nginx → tomcat):

GET /examples/websocket/echoStream HTTP/1.0
Host: 192.168.0.91
X-Real-IP: 192.168.0.98
Connection: close
User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:17.0) Gecko/20100101
Firefox/17.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Sec-WebSocket-Version: 13
Origin: http://192.168.0.91
Sec-WebSocket-Key: 9YkdANPMSHDxb8axUbeKwQ==
Pragma: no-cache
Cache-Control: no-cache

One can clearly see that there is a problem. At least, “HTTP/1.1” is
lost, “Connection: keep-alive, Upgrade” is lost, and “Upgrade:
websocket” is lost. Generally, it does not look like websocket is
supported at all (Essentially, apache does this same damage to websocket
connections).

Honestly I’m not much familiar with nginx, just had to dismiss apache
because apparently they refused to even consider support for websocket.
So before trying to dig deep into sources I thoght I should ask here. Is
it possible to get websocket through nginx really? Maybe I need to
configure something additionally?

Thank you.
Nikolai

21.02.2013 18:30, Valentin V. Bartenev wrote:
[…]

 }

Ah, this indeed helped! Now it works. Thank you very much.

Apparently such configuration implies that different kinds of
connections (standard and websocket) can not be mixed in one “location”
section? (As far as I understood it, magic headers do not get through
directly, but essentially get reintroduced by these configuration
settings?)

Thank you.
Nikolai

On Thursday 21 February 2013 18:35:14 Nikolai Zhubr wrote:

  proxy_set_header Host      $host;

Direct request (firefox → tomcat):
Origin: http://192.168.0.91:8080
Connection: close

configure something additionally?

Yes, it’s possible with 1.3.13. And yes, you need some additional
configuration.

Example:

location /examples/websocket {
    proxy_pass  http://127.0.0.1:8080;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

Docs:

Module ngx_http_proxy_module
Module ngx_http_proxy_module

wbr, Valentin V. Bartenev

http://nginx.org/en/donation.html

21.02.2013 20:03, Valentin V. Bartenev wrote:
[…]

Apparently such configuration implies that different kinds of
connections (standard and websocket) can not be mixed in one “location”
section? (As far as I understood it, magic headers do not get through
directly, but essentially get reintroduced by these configuration
settings?)

Not quite so. Actually, they can be mixed. That’s why the $http_upgrade variable
used. If there’s no such header in request, then the variable is empty and the
header won’t be set.

You are right. Now I see. I’ve even actually made some tests to be
completely sure and they all worked correctly.

Thank you for precise explanation and usefull examples!

Nikolai

On Thursday 21 February 2013 19:55:45 Nikolai Zhubr wrote:

     proxy_http_version 1.1;

directly, but essentially get reintroduced by these configuration
settings?)

Not quite so. Actually, they can be mixed. That’s why the $http_upgrade
variable
used. If there’s no such header in request, then the variable is empty
and the
header won’t be set.

You can also set the Connection header to different values depending on
existence of the Upagrade header in a request.

Example:

http {
map $http_upgrade $conn_header {
default upgrade;
‘’ close;
}

  server {
      ...

      location {
          proxy_pass  http://127.0.0.1:8080;
          proxy_http_version 1.1;
          proxy_set_header Upgrade $http_upgrade;
          proxy_set_header Connection $conn_header;
      }
  }

http://nginx.org/r/map

wbr, Valentin V. Bartenev

http://nginx.org/en/donation.html