I’m deploying a chat application that uses Ratchet as its WebSocket server. My production setup is as follows:
Web Server (Apache):
Serving my site over HTTPS on port 443 with Let’s Encrypt certificates.
My domain (meetwithchat.com) is proxied through Cloudflare.
Apache Reverse Proxy Configuration:
I configured Apache to reverse-proxy WebSocket connections from a specific path (e.g., /ws) to my Ratchet server running on localhost. My /etc/apache2/sites-available/meetwithchat.conf file is:
ServerName meetwithchat.com
ServerAlias www.meetwithchat.com
DocumentRoot /var/www/meetwithchat
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/meetwithchat.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/meetwithchat.com/privkey.pem
# Enable reverse proxy for WebSockets:
ProxyPreserveHost On
ProxyPass /ws ws://127.0.0.1:2053/
ProxyPassReverse /ws ws://127.0.0.1:2053/
ErrorLog ${APACHE_LOG_DIR}/meetwithchat_error.log
CustomLog ${APACHE_LOG_DIR}/meetwithchat_access.log combined
Ratchet WebSocket Server:
I’m running my Ratchet server without TLS (plain WebSocket) on 127.0.0.1:2053 with this server.php:
run();
?>
Client-Side Code (JavaScript):
The WebSocket is initialized in my script as follows:
ws = new WebSocket("wss://meetwithchat.com/ws");
The Issue:
When I try to connect in Chrome, I receive a Cloudflare 525 error with the message:
“SSL handshake failed. Cloudflare is unable to establish an SSL
connection to the origin server.”
I’ve also tested with OpenSSL (e.g., using port 8443 or 2053 directly), and I encounter TLS handshake failures or connection refused errors when bypassing Cloudflare. Cloudflare’s documentation states that port 2053 and 8443 are supported for HTTPS/WSS, but the issue persists.
What I’ve Tried:
Running my Ratchet server with secure (TLS) configurations directly on non‑standard ports (2053, 8443) resulted in handshake errors.
A minimal TLS test server using my Let’s Encrypt certificate works fine on my VPS when tested directly.
I attempted various TLS option adjustments (e.g., forcing STREAM_CRYPTO_METHOD_TLSv1_2_SERVER, adjusting ciphers, SNI options), but the handshake still fails when proxied through Cloudflare.
Questions:
Has anyone encountered a similar Cloudflare 525 SSL handshake error when reverse-proxying WebSockets from Apache to a Ratchet server?
What is the recommended configuration for reliably terminating TLS at Apache (or Cloudflare) and reverse-proxying WebSocket traffic to a non-TLS Ratchet server?
Are there known compatibility issues with ReactPHP’s SecureServer when using Let’s Encrypt certificates behind Cloudflare that might be causing these handshake failures?