How to get Vaadin Push work through Apache HTTP server?
Asked Answered
K

3

7

I'm trying to get Vaadin 7.1.5 Push to work on Apache Tomcat 7.0.42 + Apache HTTP server (2.2.14 with mod_proxy_wstunnel).

The Vaadin application and push with WebSocket works fine when I access Tomcat directly (ie. http://mydomain:8080/myapp). The problem arises when I try to access it by using the Apache modules mod_proxy & mod_proxy_wstunnel. What happens is that the application hangs, the loading indicator gets red and I get this error in the push request in the browser console:

HTTP Status 501 - Websocket protocol not supported
type Status report
message Websocket protocol not supported
description The server does not support the functionality needed to fulfill this request.

Apache Tomcat/7.0.42

Before Push was needed, I used mod_jk to forward requests from http://mydomain/myapp to http://mydomain:8080/myapp. Apparenly mod_jk doesn't support WebSocket so I chose to use ProxyPass directive. Here's my Apache config:

ProxyPass               /myapp/PUSH/ ws://localhost:8080/myapp/PUSH/
ProxyPassReverse        /myapp/PUSH/ ws://localhost:8080/myapp/PUSH/

ProxyPass               /myapp/VAADIN/ http://localhost:8080/myapp/VAADIN/
ProxyPassReverse        /myapp/VAADIN/ http://localhost:8080/myapp/VAADIN/
ProxyPass               /myapp http://localhost:8080/myapp
ProxyPassReverse        /myapp http://localhost:8080/myapp

I was suspecting that mod_proxy_wstunnel was to blame, but apparently it works fine when I proxy http://echo.websocket.org. I found out that the 501 error is thrown by Atmosphere, but I don't have a clue how to debug it. If I remove the ws proxy (so the push uses HTTP instead of WS), I get an instant "Session expired" error.

Does anyone know how to properly proxy push requests from Apache HTTP server to Apache Tomcat?

Kristelkristen answered 20/9, 2013 at 13:45 Comment(0)
K
4

I solved this by making sure the path of ProxyPass (and ProxyPassReverse) is identical to the context of the application and creating a new NIO connector in tomcat's server.xml config:

<Connector port="8081" protocol="org.apache.coyote.http11.Http11NioProtocol"
           connectionTimeout="20000"
           redirectPort="8443"
           proxyName="mydomain"
           proxyPort="80" />

I'm quite sure there is a way to use a path that is different from the application context, but this works for me.

UPDATE: Note that this solution doesn't work with browsers that don't support websocket (eg. IE <= 9). I suspect it has something to do with the HTTP streaming as fallback method..

Kristelkristen answered 21/9, 2013 at 9:0 Comment(0)
C
3

here is how you can do with two connectors: nio and ajp.

Tomcat config:

<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"
    connectionTimeout="20000" />

<Connector port="8009" protocol="AJP/1.3" />

Apache config with mod_rewrite and mod_proxy (and mod_proxy_wstunnel enabled) :

RewriteEngine on
RewriteCond %{QUERY_STRING} ^((?!X-Atmosphere-Transport=websocket).)*$
RewriteRule ^/PUSH(.*)$ http://app.domain.com:8080/PUSH$1 [P]

ProxyPass /PUSH ws://app.domain.com:8080/PUSH
ProxyPassReverse /PUSH ws://app.domain.com:8080/PUSH

ProxyPass / ajp://localhost:8009/
  • First, every push request that does NOT have the X-Atmosphere-Transport=websocket parameter is sent to the nio connector with the http protocol. (So streaming fallback can happen)
  • Then, other push requests (websockets) are sent to the nio connector via mod_proxy_wstunnel.
  • Other requests (non push) are sent to the ajp connector.
Clam answered 20/3, 2014 at 7:19 Comment(1)
This solution works well for both WebSocket and long-polling (and, presumably, streaming) transport. It works fine using a single HTTP[S] Tomcat connector for everything - i.e., the final line can be ProxyPass / http://app.domain.com:8080/. I did need to remove the trailing /s after PUSH.Woodie
K
2

I also ran into the this problem. The following snippet did the trick for me:

<Location /vaadinServlet/PUSH>
   Require all granted
   RewriteEngine on
   RewriteCond %{HTTP:UPGRADE} ^websocket$ [NC]
   RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
   RewriteRule .* ws://localhost:8080%{REQUEST_URI} [P]
</Location>

And you need mod_proxy_wstunnel.

I'm using Apache 2.4.10 and Vaadin 7.7.3 with Spring Boot 1.4.2 and Tomcat 8.5.6.

Kero answered 20/12, 2016 at 12:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.