1

In my Apache 2.4 vhost I'm trying to get all https:// traffic to carry on to port 443, but all ws:// traffic to forward onto ws://*:6969.

Eg:

https://example.com/index would just go to https://example.com/index:443 as normal.

ws://example.com/anypathhere/ would be forwarded to ws://example.com/anypathhere:6969

So far I've tried the commented out values in the vhost.

<VirtualHost *:443> SSLEngine on SSLCertificateFile /etc/pki/tls/certs/ca.crt SSLCertificateKeyFile /etc/pki/tls/private/ca.key DocumentRoot /var/www/html/ RewriteOptions Inherit AccessFileName .htaccess AllowEncodedSlashes NoDecode DirectoryIndex disabled <Directory /var/www/html> Options +FollowSymlinks RewriteEngine On AllowOverride All Require all granted RewriteCond %{REQUEST_FILENAME} -d RewriteRule .* %{REQUEST_URI}index.php [L] </Directory> ServerName localhost.localdomain #ProxyPreserveHost On #ProxyRequests Off #ProxyPassMatch / ws://192.16.4.177:6969/ retry=0 #ProxyPassReverse ws:// ws://192.16.4.177:6969/ #ProxyPass ws:// ws://192.16.4.177:6969/ #RewriteEngine On #RewriteRule ws:// ws://%{HTTP_HOST}/$1:6969 [NC,R=301,L] 

All of these result in

Firefox can't establish a connection to the server at ws://192.16.4.177:443 

or a 400 error.

3 Answers 3

3

You truly need to add a vhost for ws traffic which is listening on *:80

Theres is one point, which fail either with RewriteCond or with ProxyPass at the wrong VHost-File. Your traffic is encrypted by the certificate you're using. Therefore the Connection won't be established correctly. Your remote host can't read it.

Based on the documentation in wikipedia:

The communications are done over TCP port number 80 [..]

Your additional VHost-File should look like this:

<VirtualHost *:80> ServerName localhost.localdomain ProxyPreserveHost On ProxyRequests Off ProxyPassReverse / ws://192.16.4.177:6969/ ProxyPass / ws://192.16.4.177:6969/ </VirtualHost> 

As explanation. All your request going over http:80 are redirected to ws:6969.

2

The best way to do that would be to tell the client to use the right port... but if you want to proxy or redirect when they use the wrong port:

I don't know anything about ws://, but I believe you would need to use a RewriteCond for that, since a RewriteRule and similar don't contain the scheme to match. See the directive reference. This will probably only work if ws:// requests look like HTTP requets, or you have a module that specially handles ws:// requests. (To use RewriteCond, you can list it as many times as you want, and it applies only to the next RewriteRule [or similar?])

eg. for proxying:

RewriteEngine On ProxyRequests Off ProxyPreserveHost On RewriteCond %{REQUEST_SCHEME} "^ws$" RewriteRule "^(/?.*)$" ws://otherhost:6969/$1 [P] 
2

Unfortunately, I don't think there is an easy way to do this. Peter's answer doesn't work because Websockets piggybacks over HTTP(S) as an GET request with special headers. Whatever logic mod_rewrite uses to detect the URL scheme isn't smart enough to detect this, so the scheme always shows up as http or https.

In theory, you could look for the headers yourself, with something like the following syntax:

RewriteCond %{HTTP:Upgrade} ^websocket$ [nocase] RewriteRule ^(.*)$ ws://192.16.4.177:6969/$1 [proxy] 

However, while this rule does match the opening client handshake (confirmed in my logs), this doesn't give me a working Websocket redirect. I suspect that mod_rewrite doesn't actually understand how to proxy Websocket connections, even if you can get the handshake to go to the right place.

That leaves us with JinnFox's answer. If you are able to move your Websockets endpoint to somewhere other than /, that might be an acceptable solution.

P.S. In the mean time, I have found that NGINX handles this case nearly seamlessly (scroll down to step 6 to find a code snippet that works for both HTTP and WS).

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.