Hello,
I made a WebSocket service in Apache under CentOs with PHP and JS that works great if the protocol is ws:// . The problem is that the site is served through https:// so I must use wss protocol (cause mixed content policy). I have tried many approaches to make it work and any idea would really help.

First I tried to bind the socket of the WS (WebSocket) Server to 443 , but I got permission denied. The next thing was trying to alternate httpd.conf through include file to make every communication made in this server IP though a certain port e.g. 9100 to use a certain crt key and cabundle files. I made it copying the VirtualHost entry for the domain when it uses https , port 443 . But I am stack , I cant find a way to make Apache treat the communication to a certain IP and port (for a single domain or not) with the same ssl encode and decode files as the one used in the domain https 443 port.

Any idea in the way I am searching it , or in an alternate way would be great. Thank you in advance

Dani AI

Generated

Short answer: terminate TLS at Apache and proxy WSS to your PHP WebSocket server on an internal port (e.g. 9100). Browsers will block an insecure ws:// load from an https:// page, and the WebSocket starts as an HTTP(S) GET that is upgraded to the WebSocket protocol — so the TLS handshake must happen on the initial connection. The "permission denied" when binding to 443 is expected on Linux because ports < 1024 are privileged. (developer.mozilla.org)

A practical and low-risk setup is: let Apache (port 443) hold the SSL certs and act as the TLS terminator, then proxy WebSocket upgrade requests to your PHP server on 127.0.0.1:9100. Enable mod_ssl, mod_proxy and mod_proxy_wstunnel, and use a VirtualHost like:

<VirtualHost *:443>
  ServerName example.com
  SSLEngine on
  SSLCertificateFile /path/to/cert.pem
  SSLCertificateKeyFile /path/to/key.pem

  ProxyPreserveHost On
  ProxyPass "/ws"  "ws://127.0.0.1:9100/"
  ProxyPassReverse "/ws"  "ws://127.0.0.1:9100/"
</VirtualHost>

This converts wss://example.com/ws to plain ws://127.0.0.1:9100. (httpd.apache.org)

Alternatives: run an SSL wrapper like stunnel in front of your PHP server, or grant a binary CAP_NET_BIND_SERVICE / use authbind so it can bind 443 without running as root — but those carry operational and update/permission caveats, so prefer proxy/TLS termination in Apache for security and simplicity. (stunnel.org)

Notes for : is right about the Upgrade handshake; the Apache reverse-proxy pattern above is the common solution on CentOS and avoids running your WebSocket daemon as root.

Recommended Answers

All 2 Replies

If I recall, a websocket is just an HTTP request that gets upgraded to a persistent connection. I haven't read the spec entirely, but it's much like a 302 response, but for the WS upgrade.

Hello ryantroop , indeed websocket communication does a HTTPS or HTTP request for switching protocols. I've never had any problem with this first request when using http and ws protocols , the problem is with wss. I though that there must be an easy solution , in httpd.conf you just tell apache with VirtualHost that if the request came from 443 in a certain IP for a certain domain then to use a crt , key and cabundle files to do the encoding / decoding back stage. So there should be a way to tell the same if any request comes to another port (lets say 9100). The difference is that in first case runs the apache daemon that “hear” for request in 443 and in the latter there is a server daemon that you just build and bind it in a port. Although there must be a way with apache my knowledge to apache is limited so I am swifting the issue to PHP that there I know how to do it (I just have to rewrite the server daemon once again) , and I would prefer to have the server do the encoding / decoding for ssl communication than PHP.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.