In this guide are going to install and configure Apache, mod_proxy and proxy_wstunnel. proxy_wstunnel is required if you want successfully connect to WildFly via websockets (thru Apache). Any attempt to connect via websockets without proxy_wstunnel will fail as the HTTP Upgrade headers will be removed from your request.
Apache install
First install Apache and the required mods:sudo apt-get install apache2 sudo apt-get install libapache2-mod-proxy-html sudo a2enmod proxy_http sudo a2enmod proxy_wstunnel sudo /etc/init.d/apache2 restart
Apache configuration
Now configure your VirtualHost. For simplicity we are going to update the 000-default.conf file. In this example the context root of the application is app. Update yours as needed.vim /etc/apache2/sites-available/000-default.conf
These two lines are required to proxy your main http connections
ProxyPass /app http://localhost:8080/pss ProxyPassReverse /app http://localhost:8080/pss
These two lines will proxy your websocket connections
ProxyPass /app/ws/ ws://localhost:8080/app/ws/ ProxyPassReverse /app/ws/ ws://localhost:8080/app/ws/
Here is the full VirtualHost file, with the mod_proxy and proxy_wstunnel configuration highlighted:
<VirtualHost *:80> ServerName www.example.com ServerAlias example.com ServerAdmin webmaster@localhost DocumentRoot /var/www/example.com ProxyPass /app http://localhost:8080/pss ProxyPassReverse /app http://localhost:8080/pss ProxyPass /app/ws/ ws://localhost:8080/app/ws/ ProxyPassReverse /app/ws/ ws://localhost:8080/app/ws/ ErrorLog ${APACHE_LOG_DIR}/example.com-error.log CustomLog ${APACHE_LOG_DIR}/example.com-access.log combined </VirtualHost>Reload Apache for the changes to take effect
sudo /etc/init.d/apache2 reload
Java configuration
Make sure that the value you pass into your @ServerEndPoint annotation matches that in your Apache VirtualHost configuration.@ServerEndpoint("/ws") public class WebSocketEndpoint { private final Logger logger = Logger.getLogger(this.getClass().getName()); @OnOpen public void onConnectionOpen(Session session) { logger.info("Connection opened"); } @OnMessage public String onMessage(String message) { return "Message received"; } @OnClose public void onConnectionClose(Session session) { logger.info("Connection closed"); } }
WildFly configuration
Make sure that you allow connections to your public interface from localhost (127.0.0.1) only. While this is not mandatory, leaving it open will allow connections to circumvent Apache.<interfaces> <interface name="management"> <inet-address value="0.0.0.0"/> </interface> <interface name="public"> <inet-address value="${jboss.bind.address:127.0.0.1}"/> </interface> <interface name="unsecure"> <inet-address value="${jboss.bind.address.unsecure:127.0.0.1}"/> </interface> </interfaces>In WildFly websockets work out of the box, so no other configuration required. Here is the default undertow configuration, with the relevant parts highlighted.
<subsystem xmlns="urn:jboss:domain:undertow:1.2"> <buffer-cache name="default"/> <server name="default-server"> <http-listener name="default" socket-binding="http"/> <host name="default-host" alias="localhost"> <location name="/" handler="welcome-content"/> <filter-ref name="server-header"/> <filter-ref name="x-powered-by-header"/> </host> </server> <servlet-container name="default"> <jsp-config/> <websockets/> </servlet-container> </subsystem>You should now be able to deploy your websocket applications to WildFly and access them via Apache.
Hi Chris,
ReplyDeleteI wonder what your take is on a couple of issues I faced regarding this topic:
- Would you consider using AJP instead of HTTP between Apache and Wildfly? My understanding is that AJP offers better performance.
- When securing the outside traffic (using SSL/TLS, always a good idea IMHO), would you have Apache offload the encryption (i.e. end encryption at Apache and connect unencrypted to Wildfly) or carry the encryption up to Wildfly?
Thanks,
Maurice
Hi Maurice, thanks for the message.
DeleteI find HTTP easier to set up and configure. AJP is designed to communicate between the web server and the application server, so in theory, should be better performing. Also, if you use mod_proxy_http the host headers will be stripped out where as the headers will be preserved with AJP. (For example you will loose your HTTP Upgrade)
To keep the headers with HTTP you need to use 'ProxyPreserveHost On' in you Apache config.
With regards to your SSL question. I have always installed my SSL certs in Apache and let Apache deal with the encryption. I then forward the traffic to WildFly using HTTP. I have favoured this approach as I can quickly configure Apache SSL. Also when I upgrade my JBoss/WildFly server I have less to configure. I suppose it comes down to personal preference.
Hi Chris...
ReplyDeleteMy environment is Wildfly 8.2 and Apache 2.2.21
I did the following things and I couldnt get this work...
1)I enabled proxy_wstunnel_module (shared)
2)I disabled mod_proxy_ajp.so due to AJP is not compatible with websocket according to documentation
3)I am using Atmosphere Websocket with wildfly...
My web.xml config is:
Push Servlet
org.primefaces.push.PushServlet
org.atmosphere.cpr.broadcasterCacheClass
org.atmosphere.cache.UUIDBroadcasterCache
0
true
Push Servlet
/primepush/*
About my EndPoint is @PushEndpoint("/{primepush}/{user}")
4) I changed my subsystem wildfly config from AJP to HTTP
5)I created my reverse proxies:
ProxyPass /company http://app.tiedocs.com/company
ProxyPassReverse /company http://asubdomain.website.com/company
ProxyPass /company/primepush/ ws://subdomain.website.com/company/primepush/
ProxyPassReverse /company/primepush/ ws://subdomain.website.com/company/primepush/
ProxyPass /company http://localhost:8080/company
ProxyPassReverse /company http://localhost:8080/company
ProxyPass /company/primepush/ ws://localhost:8080/company/primepush/
ProxyPassReverse /company/primepush/ ws://localhost:8080/company/primepush/
But ever, I'm still getting the same error UT000077: The underlying transport does not support HTTP upgrade..
I dont know exactly what I'm doing wrong.
At the time of this answer AJP [which is the default one] does not support HTTP upgrade and hence not websocket.
ReplyDeleteIf you switch to HTTP websocket will work.
Following changes you need to do to switch to AJP
Change
LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
#LoadModule proxy_http_module modules/mod_proxy_http.so
To
#LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
LoadModule proxy_http_module modules/mod_proxy_http.so
[comment out proxy_ajp_module and added proxy_http_module]
In modcluster sub-system
Change
To
[“default” is the name of the http listener]
Also you need to load mod_proxy_wstunnel in your httpd
Thx for this scripts, it's very useful, I thinking abot using it in my dissertation work, if y don't mind.
ReplyDeleteBest regards
Toby, data room solutions