Fixing WebSocket Handshake Failures in Apache2 with SpringBoot

Fixing WebSocket Handshake Failures in Apache2 with SpringBoot

Recently, I encountered an issue while setting up WebSocket connections through an Apache reverse proxy to Spring Boot application.

The error message in application log like below.

2025-02-18 17:01:05.255 ERROR 242411 --- [nio-8080-exec-2] o.s.w.s.s.s.DefaultHandshakeHandler      : "Handshake failed due to invalid Upgrade header: null"

This error occurs when WebSocket connection fails to establish properly through Apache2 reverse proxy.

The Problem

When running Spring Boot application behind an Apache reverse proxy, Websocket requires special handling. The default Apache2 configuration doesn’t automatically support Websocket protocol upgrade process, leading to the handshake failures.

In my case, the WebSocket client was trying to connect to:

wss://dttracking.phamanhduc.com/gps-socket/245/nbllozux/websocket

The Solution

The fix involves modifying the Apache virtual host configuration to properly support WebSocket connections. Here’s the solution:

1. Ensure have the necessary Apache modules installed

sudo a2enmod proxy
sudo a2enmod proxy_wstunnel
sudo a2enmod proxy_http

2. Update Apache virtual host configuration file (typically found in /etc/apache2/sites-available/)

<IfModule mod_ssl.c>
<VirtualHost *:443>
    ServerName dttracking.phamanhduc.com
    
    # Enable required modules
    LoadModule proxy_module modules/mod_proxy.so
    LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
    LoadModule proxy_http_module modules/mod_proxy_http.so
    
    ProxyPreserveHost On
    
    # WebSocket specific configuration
    RewriteEngine On
    RewriteCond %{HTTP:Upgrade} websocket [NC]
    RewriteCond %{HTTP:Connection} upgrade [NC]
    RewriteRule ^/gps-socket/(.*) ws://localhost:8080/gps-socket/$1 [P,L]
    
    ....

</VirtualHost>
</IfModule>

3. After making the changes, test the configuration and restart Apache

sudo apache2ctl configtest
sudo systemctl restart apache2

Key components Explained

Let’s break down the important parts of this configuration:

  1. Module loading: The configuration ensure that necessary modules for proxying and WebSocket support are available
  2. WebSocket Rules: The RewriteEngine rules specifically handle Websocket connections:
    • Check for Upgrade: websocket header
    • Check for Connection: upgrade header
    • Forward WebSocket connections to the appropriate backend endpoints. In my case is: ws://localhost:8080/gps-socket

Conclution

If you’re implementing WebSockets in your Spring Boot application, this configuration should help you avoid the common pitfall of handshake failures through Apache reverse proxy.

Document