Reputation: 46351
I have :
Apache 2.4 on port 80 of my server, with mod_proxy and mod_proxy_wstunnel enabled
Node.js + socket.io
on port 3001 of the same server
Accessing example.com
(with port 80) redirects to 2. thanks to this method with the following Apache configuration:
<VirtualHost *:80>
ServerName example.com
ProxyPass / http://localhost:3001/
ProxyPassReverse / http://localhost:3001/
ProxyPass / ws://localhost:3001/
ProxyPassReverse / ws://localhost:3001/
</VirtualHost>
It works for everything, except the WebSocket part : ws://...
are not transmitted like it should by the proxy.
When I access the page on example.com
, I have:
Impossible to connect ws://example.com/socket.io/?EIO=3&transport=websocket&sid=n30rqg9AEqZIk5c9AABN.
Question: How to make Apache proxy the WebSockets as well?
Upvotes: 137
Views: 222783
Reputation: 27812
First, activate required Apache modules:
a2enmod proxy
a2enmod proxy_http
a2enmod proxy_wstunnel
Then with the following template Apache reverse proxy site configuration (using the conventional host-port combination localhost:3000
), socket.io websockets work (adapted from the official socket.io v4 documentation):
<VirtualHost *:80>
# redirect anything HTTP-without-S to HTTPS-with-S
ServerName websocket.example.com
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
# see https://httpd.apache.org/docs/2.4/rewrite/flags.html
# see https://httpd.apache.org/docs/2.4/mod/mod_rewrite.html#rewriterule
ErrorLog ${APACHE_LOG_DIR}/websocket-http-error.log
CustomLog ${APACHE_LOG_DIR}/websocket-http-access.log combined
</VirtualHost>
<VirtualHost *:443>
ServerName websocket.example.com
SSLEngine On
SSLProxyCheckPeerName On
# assuming let's encrypt certificate
SSLCertificateFile /etc/letsencrypt/live/websocket/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/websocket/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/websocket/chain.pem
ProxyPass / http://localhost:3000/
ProxyPassReverse / http://localhost:3000/
# setup websocket socket.io configuration
# see https://socket.io/docs/v4/reverse-proxy/#apache-httpd
RewriteEngine on
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{HTTP:Connection} upgrade [NC]
RewriteRule ^/?(.*) "ws://localhost:3000/$1" [P,L]
ProxyTimeout 3
ErrorLog ${APACHE_LOG_DIR}/websocket-https-error.log
CustomLog ${APACHE_LOG_DIR}/websocket-https-access.log combined
</VirtualHost>
Upvotes: 1
Reputation: 46351
I finally managed to do it, thanks to this topic. TODO:
1) Have Apache 2.4 installed (doesn't work with 2.2), and do:
a2enmod proxy
a2enmod proxy_http
a2enmod proxy_wstunnel
2) Have nodejs
running on port 3001
3) Do this in the Apache config
<VirtualHost *:80>
ServerName example.com
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/socket.io [NC]
RewriteCond %{QUERY_STRING} transport=websocket [NC]
RewriteRule /(.*) ws://localhost:3001/$1 [P,L]
ProxyPass / http://localhost:3001/
ProxyPassReverse / http://localhost:3001/
</VirtualHost>
Note: if you have more than one service on the same server that uses websockets, you might want to do this to separate them.
Upvotes: 201
Reputation: 177
For the same issue on Windows, just uncomment the below line from http.conf:
Then add the below line to your apache config:
LoadModule proxy_module modules/mod_proxy_wstunnel.so
Upvotes: 1
Reputation: 227
My setup:
/api/ws
As mentioned above by @Basj, make sure a2enmod proxy and ws_tunnel are enabled.
This is a screenshot of the Apache config file that solved my problem:
The relevant part as text:
<VirtualHost *:80>
ServerName *******
ServerAlias *******
ProxyPass / http://localhost:3000/
ProxyPassReverse / http://localhost:3000/
<Location "/api/ws">
ProxyPass "ws://localhost:3000/api/ws"
</Location>
</VirtualHost>
Hope that helps.
Upvotes: 8
Reputation: 47
User this link for perfact solution for ws https://httpd.apache.org/docs/2.4/mod/mod_proxy_wstunnel.html
You have to just do below step..
Go to /etc/apache2/mods-available
Step...1
Enable mode proxy_wstunnel.load
by using below command
$a2enmod proxy_wstunnel.load
Step...2
Go to /etc/apache2/sites-available
and add below line in your .conf file inside virtual host
ProxyPass "/ws2/" "ws://localhost:8080/"
ProxyPass "/wss2/" "wss://localhost:8080/"
Note : 8080 mean your that your tomcat running port because we want to connect ws
where our War file putted in tomcat and tomcat serve apache for ws
.
thank you
My Configuration
ws://localhost/ws2/ALLCAD-Unifiedcommunication-1.0/chatserver?userid=4 =Connected
Upvotes: 2
Reputation: 3244
For me it works after adding only one line in httpd.conf as below (bold line).
<VirtualHost *:80>
ServerName: xxxxx
#ProxyPassReverse is not needed
ProxyPass /log4j ws://localhost:4711/logs
<VirtualHost *:80>
Apache version is 2.4.6 on CentOS.
Upvotes: 10
Reputation: 6183
Did the following for a spring application running static, rest and websocket content.
The Apache is used as Proxy and SSL Endpoint for the following URIs:
<VirtualHost *:80>
ServerName xxx.xxx.xxx
ProxyRequests Off
ProxyVia Off
ProxyPreserveHost On
<Proxy *>
Require all granted
</Proxy>
RewriteEngine On
# websocket
RewriteCond %{HTTP:Upgrade} =websocket [NC]
RewriteRule ^/api/ws/(.*) ws://localhost:8080/api/ws/$1 [P,L]
# rest
ProxyPass /api http://localhost:8080/api
ProxyPassReverse /api http://localhost:8080/api
# static content
ProxyPass /app http://localhost:8080/app
ProxyPassReverse /app http://localhost:8080/app
</VirtualHost>
I use the same vHost config for the SSL configuration, no need to change anything proxy related.
server.use-forward-headers: true
Upvotes: 9
Reputation: 46351
In addition to the main answer: if you have more than one service on the same server that uses websockets, you might want to do this to separate them, by using a custom path (*):
Node server:
var io = require('socket.io')({ path: '/ws_website1'}).listen(server);
Client HTML:
<script src="/ws_website1/socket.io.js"></script>
...
<script>
var socket = io('', { path: '/ws_website1' });
...
Apache config:
RewriteEngine On
RewriteRule ^/website1(.*)$ http://localhost:3001$1 [P,L]
RewriteCond %{REQUEST_URI} ^/ws_website1 [NC]
RewriteCond %{QUERY_STRING} transport=websocket [NC]
RewriteRule ^(.*)$ ws://localhost:3001$1 [P,L]
RewriteCond %{REQUEST_URI} ^/ws_website1 [NC]
RewriteRule ^(.*)$ http://localhost:3001$1 [P,L]
(*) Note: using the default RewriteCond %{REQUEST_URI} ^/socket.io
would not be specific to a website, and websockets requests would be mixed up between different websites!
Upvotes: 6
Reputation: 47
TODO:
Have Apache 2.4 installed (doesn't work with 2.2), a2enmod proxy
and a2enmod proxy_wstunnel.load
Do this in the Apache config
just add two line in your file where 8080 is your tomcat running port
<VirtualHost *:80>
ProxyPass "/ws2/" "ws://localhost:8080/"
ProxyPass "/wss2/" "wss://localhost:8080/"
</VirtualHost *:80>
Upvotes: 0
Reputation: 6430
For "polling" transport.
Apache side:
<VirtualHost *:80>
ServerName mysite.com
DocumentRoot /my/path
ProxyRequests Off
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
ProxyPass /my-connect-3001 http://127.0.0.1:3001/socket.io
ProxyPassReverse /my-connect-3001 http://127.0.0.1:3001/socket.io
</VirtualHost>
Client side:
var my_socket = new io.Manager(null, {
host: 'mysite.com',
path: '/my-connect-3001'
transports: ['polling'],
}).socket('/');
Upvotes: 1
Reputation: 372
With help from these answers, I finally got reverse proxy for Node-RED running on a Raspberry Pi with Ubuntu Mate and Apache2 working, using this Apache2 site config:
<VirtualHost *:80>
ServerName nodered.domain.com
RewriteEngine On
RewriteCond %{HTTP:Upgrade} =websocket [NC]
RewriteRule /(.*) ws://localhost:1880/$1 [P,L]
RewriteCond %{HTTP:Upgrade} !=websocket [NC]
RewriteRule /(.*) http://localhost:1880/$1 [P,L]
</VirtualHost>
I also had to enable modules like this:
sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod proxy_wstunnel
Upvotes: 10
Reputation: 2422
As of Socket.IO 1.0 (May 2014), all connections begin with an HTTP polling request (more info here). That means that in addition to forwarding WebSocket traffic, you need to forward any transport=polling
HTTP requests.
The solution below should redirect all socket traffic correctly, without redirecting any other traffic.
Enable the following Apache2 mods:
sudo a2enmod proxy rewrite proxy_http proxy_wstunnel
Use these settings in your *.conf file (e.g. /etc/apache2/sites-available/mysite.com.conf
). I've included comments to explain each piece:
<VirtualHost *:80>
ServerName www.mydomain.com
# Enable the rewrite engine
# Requires: sudo a2enmod proxy rewrite proxy_http proxy_wstunnel
# In the rules/conds, [NC] means case-insensitve, [P] means proxy
RewriteEngine On
# socket.io 1.0+ starts all connections with an HTTP polling request
RewriteCond %{QUERY_STRING} transport=polling [NC]
RewriteRule /(.*) http://localhost:3001/$1 [P]
# When socket.io wants to initiate a WebSocket connection, it sends an
# "upgrade: websocket" request that should be transferred to ws://
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteRule /(.*) ws://localhost:3001/$1 [P]
# OPTIONAL: Route all HTTP traffic at /node to port 3001
ProxyRequests Off
ProxyPass /node http://localhost:3001
ProxyPassReverse /node http://localhost:3001
</VirtualHost>
I've included an extra section for routing /node
traffic that I find handy, see here for more info.
Upvotes: 24
Reputation: 7548
Instead of filtering by URL, you can also filter by HTTP header. This configuration will work for any web applications that use websockets, also if they are not using socket.io:
<VirtualHost *:80>
ServerName www.domain2.com
RewriteEngine On
RewriteCond %{HTTP:Upgrade} =websocket [NC]
RewriteRule /(.*) ws://localhost:3001/$1 [P,L]
RewriteCond %{HTTP:Upgrade} !=websocket [NC]
RewriteRule /(.*) http://localhost:3001/$1 [P,L]
ProxyPassReverse / http://localhost:3001/
</VirtualHost>
Upvotes: 130
Reputation: 5207
May be will be useful. Just all queries send via ws to node
<VirtualHost *:80>
ServerName www.domain2.com
<Location "/">
ProxyPass "ws://localhost:3001/"
</Location>
</VirtualHost>
Upvotes: 24