Configure Apache Web Server for Websockets using Reverse Proxy

This article provides basic steps to configure Apache Web Server to work with Websockets.

We recently created a Spring based web application that uses web sockets for live streaming of data from the Tomcat 8.x server. Everything was working fine with localhost or when the web application was accessed directly from Tomcat but when Tomcat was accessed using a load balancer (in our case Apache Web Server) web sockets suddenly stopped working.

After our research, we found that Apache Web Server configurations need to be done to get it working. In general, it is called WebSocket reverse proxying (“Reverse Proxy” settings with “wstunnel”).

After a successful configuration, it worked and I just thought to put minimal steps on a web page so it can help others (and we don’t forget as well).

Note:

With this example, it is assumed that both your backend application and the Apache Web Server are running on the same host.

Setup

Tomcat 8.5.5
SpringBoot (2.0.3) with Angular 6.x
SockJS for Websockets with Angular
Apache Http web server (2.4.41)
OS: macOS 10.15.x & Windows 10

Apache Web Server Installation

macOS already have Apache Web Server installed and it can be accessed using “apachectl” command over terminal. Some useful commands-

apachectl start
apachectl stop
apachectl restart
apachectl -v
apachectl status

For windows, It needs to be installed manually. Since officially there’s no MSI for installation and it needs compilation but there are many good third-party wrappers those provide everything we need, for example, WampServerXMPP.

For detailed installation steps please follow the official Apache Web Server installation page.

Let’s start

In general, below settings apply to all OSes (as the same file needs to be updated) however some OSes (servers like CentOS, Ubuntu, etc) might need extra configurations and those are not covered here.

Open the httpd.confg file available at –

macOS – /private/etc/apache2
Windows – apache-server-installation-root-direcotry/config

Enable below module in config file (remove # from the beginning of the line) –

LoadModule proxy_module libexec/apache2/mod_proxy.so
LoadModule proxy_http_module libexec/apache2/mod_proxy_http.so
LoadModule proxy_wstunnel_module libexec/apache2/mod_proxy_wstunnel.so
LoadModule rewrite_module libexec/apache2/mod_rewrite.so

To enable Reverse proxying support, we will have to create a Virtual Host. Below is an example to create HTTP virtual host having ReverseProxy and Rewrite engine on.

Copy below host configurations as it is to httpd.conf file, you can insert anywhere (but after module load definitions) but to maintain document integrity and format add it after line having “ServerAdmin” settings (search for it).

HTTP Virtual Host

<VirtualHost *:80>
  ServerName my-proxy.com
  
  ProxyRequests on
  RequestHeader set X-Forwarded-Proto "http"	
  ProxyPass / https://localhost:9090/
  ProxyPassReverse / https://localhost:9090/  

  RewriteEngine on
  RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
  RewriteCond %{HTTP:CONNECTION} ^Upgrade$ [NC]
  RewriteRule .* ws://localhost:9090%{REQUEST_URI} [P]
  
</VirtualHost>

Apache Web Server VirtualHost configuration for Websockets

For understanding, below are the details of the important directive and its usage. It is worth to mention that tomcat is running on the system over port 9090 and it is accessible using http://localhost:9090.

ServerName
Virtual host server name, in other words, publically exposed hostname (domain) for your website (like aripratech.com) and typically your WebSockets connections will be initiated from.

RewriteEngine on
Sets the status of the RewriteEngine to either on or off. For WebSockets, it must be on.

RewriteCond ${HTTP:Upgrade} websocket [NC]
This condition must be matched in order for a request to be processed by the RewriteRule.

RewriteCond ${HTTP:Connection} upgrade [NC]
This condition should also match, connection should request “upgrade” method for establisting connection.

RewriteRule .* ws://localhost:9090%{REQUEST_URI} [P]
If the above condition matches, Rewrite all incoming requests to use the ws protocol and replace the destination hostname to that of a backend service.

Once this is done, restart the Apache Web Server and WebSockets should work now.

Make sure to save the httpd.conf file.