14

I couldn't connect my websocket using wss://.

I found that there is a way to use Apache to expose

  • wss://domain.com - frontend (Apache)
  • ws://domain.com:9090 - backend plaintext

My configuration:

ProxyPass        /websocket ws://domain.com:9090
ProxyPassReverse /websocket ws://domain.com:9090

This code in apache config will send request from any address ended with /websocket to ws://domain.com:9090 ex: ws://websocket will be ws://domain.com:9090

I want to do it for wss:// also. Example: wss://websocket must point to ws://domain.com:9090.

It doesn't work and I get this error in browser console:

failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED

Is there any mistake here? Thanks you.

Valerio Bozz
  • 1,176
  • 16
  • 32
Sam Rad
  • 451
  • 2
  • 5
  • 13

8 Answers8

21

i worked 24 hours for find this and searched a lot of forum but no one write about success. here is my server configuration :

CentOS release 6.7 , Apache 4.2.18

here is what i did finally : first i found that modules/mod_proxy_wstunnel.so must be enable in apache config file , but my apache didn't have that module and after a lot of search i found that module is Available in apache 2.4.5 and later.

https://httpd.apache.org/docs/2.4/mod/mod_proxy_wstunnel.html

i downloaded https://archive.apache.org/dist/httpd/httpd-2.4.18.tar.gz extracted httpd-2.4.18\modules\proxy\mod_proxy_wstunnel.c and uploaded to my server root then from terminal could compile it again with these commonds :

chmod 755 mod_proxy_wstunnel.c #set permission
pxs -i -a -c mod_proxy_tunnel.c #compile module

pxs command did compile the module and wrote in apache config file to load it

LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so

after that i added these lines to end of apache config file :

RewriteEngine on
ProxyRequests Off
ProxyPreserveHost on
ProxyPass /myws ws://mysite.com:8091
ProxyPassReverse /myws ws://mysite.com:8091

AND NOW : it works ! in client side js you can set ws url like this :

var protocol = 'ws://'; 
if (window.location.protocol === 'https:') {
            protocol = 'wss://';
   }

 var wsUri =protocol+ "mysite.com/myws";  

 var ws = new WebSocket(wsUri);

and it will forward request to ws://mysite.com:8091 doesnt matter the page loaded with https or http , it will direct all request ended with /myws to ws://mysite.com:8091

Sam Rad
  • 451
  • 2
  • 5
  • 13
  • 1
    I am trying to configure a proxy to catch wss requests and redirect it throw ws to my Server for Dev environnment needs. I don't really understand what you did. I already activated mod_proxy and mod_proxy_tunnel (I am on apache2 2.4.10). Now i have to change my apache config (I tried in .htaccess). It Doesn't works, I have an 500 internal server error. And i don't really understand the lines : ProxyPass /myws ws://mysite.com:8091 ProxyPassReverse /myws ws://mysite.com:8091 For you, what is mysite.com? the address of the websocket serveur? – Sphinx117 Aug 08 '17 at 15:08
19

You need to enable some Apache2 modules:

$ a2enmod proxy proxy_wstunnel proxy_http rewrite

Then you can use this configuration to solve your problem.

    ProxyRequests off
    ProxyVia on      
    RewriteEngine On

    RewriteEngine On
    RewriteCond %{HTTP:Connection} Upgrade [NC]
    RewriteCond %{HTTP:Upgrade} websocket [NC]
    RewriteRule /(.*) ws://example.com:9090/$1 [P,L]

    ProxyPass               /websocket http://example.com:9090/websocket
    ProxyPassReverse        /websocket http://example.com:9090/websocket

Apache2 automatically upgrades the connection to websocket with ws://, you don't need to set the ws:// manually. I tried dozens of configurations and this is the only one that worked for me.

  • 1
    oh my GOD thank you so much for that. I've searched high and low, this one did the trick. – MitchEff Feb 18 '21 at 09:46
  • So finally after 5 days, My Hackathon to find right answer is ended. I must create a video tutorial for this bug. and how to get over it. Thanks @florian – optimists Apr 12 '22 at 06:34
  • Was working for me too after almost an hour of trial and error. Added it to the docs and backlinked to here. https://github.com/Koenkk/zigbee2mqtt.io/pull/1924 – JulianW Feb 27 '23 at 02:17
3

the problem I was trying to solve was similar to this one. I have a reverse proxy running under Apache 2.4 on CentOs 7 which has to work with both https and wss requests.

Behind the reverse proxy I have my app server running on an internal network. the virtual host configuration in the /etc/httpd/httpd.conf config file is as follows:

<VirtualHost *:443>
   ServerName example.com
   RewriteCond %(HTTP:Upgrade) websocket [NC]   # Required to handle the websocket connection
   RewriteCond %(HTTP:Connection) upgrade [NC]
   RewriteRule /(.*) ws://192.160.0.1/$1 [P,L]

  SSLEngine on # SSL Certificates handling
  SSLCertificateFile ssl/cert.pem # Public Certificate
  SSLCertificateKeyFile ssl/key.pem # Private certificate
  SSLCertificateChainFile ssl/ca.pem # CA or chain certificate

 ProxyPreserveHost On
 ProxyPass /websocket ws://192.168.0.1 # First you need to write the specific rules
 ProxyPassReverse /websocket ws://102.168.0.1
 ProxyPass / http://192.168.0.1 # Then the generic rules for the proxy.
 ProxyPassReverse / http://192.168.0.1
 </VirtualHost>

In your case, you will have to replace the ServerName, the SSL certificates location, and the destination of the proxy.

1

wss needs following module Uncomment line at the httpd.conf of apache conf LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so

Vinayak Shedgeri
  • 2,222
  • 1
  • 21
  • 24
0

The /websocket path is missing in your ProxyPass configuration path.

Use:

ProxyPass /websocket ws://example.com:9090/websocket
ProxyPassReverse /websocket ws://example.com:9090/websocket

Additional information: Like others mentioned, you have to uncomment the line:

LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so

If you are also using a http ProxyPass thats relative path is "/" (forwarding everything directly), the specific "/websocket" path configuration must be configured first, otherwise "/" grabs first.

ProxyPass /websocket ws://example.com:9090/websocket
ProxyPassReverse /websocket ws://example.com:9090/websocket

ProxyPass balancer://ac-cluster/
ProxyPassReverse / http://example.com:9090
Ruwen
  • 3,008
  • 1
  • 19
  • 16
0

I did it for aria 2. I just enabled some modules and added a single line to config. (env: debian buster/apache 2.4). enabling modes:

sudo a2enmod proxy proxy_balancer proxy_wstunnel proxy_http

and add this line to ssl site config file inside the virtual host directive :

ProxyPass /jsonrpc ws://127.0.0.1:6888/jsonrpc
MSS
  • 3,520
  • 24
  • 29
0

There is another approach using the <Location> blocks to have shorter configurations and more readable.

If you want a frontend webserver with HTTPs support (with Apache HTTPd) to proxy request to an underlying backend webserver in plaintext, here a possibility:

#
# https://example.com/websocket   -> [Apache:443] -> Websocket plaintext -> [Backend websocket:9000]
# https://example.com/other-stuff -> [Apache:443] -> HTTP      plaintext -> [Backend webserver:8080]
#
<VirtualHost *:443>
    ServerName example.com

    DocumentRoot /var/www/html

    # My application without websocket (if you have that)
    <Location />
        # This can be a Docker container, PHP-FPM, Tomcat, etc.
        ProxyPass        http://localhost:8080/
        ProxyPassReverse http://localhost:8080/
    </Location>

    # Plaintext websockets handled by their dedicated path
    <Location /websocket>
        ProxyPass ws://localhost:9090/
    </Location>

    SSLEngine on
    SSLCertificateFile      ssl/cert.pem # Public Certificate
    SSLCertificateKeyFile   ssl/key.pem  # Private certificate
    SSLCertificateChainFile ssl/ca.pem   # CA or chain certificate

</VirtualHost>

The example also tried to show how to integrate your HTTP web application with your websocket, since that is a frequent issue.

How and Why it works

Here some reference from official documentation:

When used inside a section, the first argument is omitted and the local directory is obtained from the .

https://httpd.apache.org/docs/2.4/mod/mod_proxy.html#ProxyPass

Also note that very probably you do not need any ProxyPassReverse in the websocket location since in theory it does not have sense there.

Also note that usually you just need to write ProxyPass ws://localhost:9090/ and not ProxyPass ws://localhost:9090/websocket or something, since the backend websocket server usually has no location.

This answer was useful at least in Apache/2.4.6 but probably in other versions.

Troubleshooting

If it does not work, search the errors logs of your Apache HTTPd webserver. This really deserves a dedicated research and cannot be clarified here.

Try to isolate the problem to see if you have a problem with proxies in general, or just with websocket.

Valerio Bozz
  • 1,176
  • 16
  • 32
-2

I want to share this in case it helps somebody else avoid days of wasted time and effort.

I was giving up after researching everything. I was ready to start following the code of the different proxy modules, yes I know, a spiderweb..., but I was desperate. As a last resource I installed wireshark to follow exactly what was going on in my network. After installing wireshark, the instructions asked me to restart my server through a power off/on cycle. So, I did. When I started tracing it, to my complete surprise, the server was proxying perfectly the wss requests to ws, no problems! So I had the correct setup to start with but something got messed up in Ubuntu 20.4 / Apache 2.4.41 / node 14.17.2 that required a complete restart of the machine where the server operates. Crazy! But that was it...

Julio Spinelli
  • 587
  • 3
  • 16