Desmond
Desmond

Reputation: 149

Running Socket.io over Apache Reverse Proxy

I am trying to run NodeJS behind Apache and so far I am stuck with Socket.io issue.

I have no issue accessing the application directly, but whenever I accessed through my domain, I get this error thrown from socket.io:

Firefox can’t establish a connection to the server at wss://example.com/socket.io/?EIO=3&transport=websocket&sid=X-hLU73t7ojk2zoRAAAB.

My Apache configuration is as follows:

     <VirtualHost _default_:443>
            ServerName example.com

            ErrorLog ${APACHE_LOG_DIR}/error.log
            CustomLog ${APACHE_LOG_DIR}/access.log combined

            SSLEngine on

            SSLCertificateFile      /etc/ssl/certs/apache-selfsigned.crt
            SSLCertificateKeyFile /etc/ssl/private/apache-selfsigned.key


            ProxyRequests off
            ProxyVia on

            RewriteEngine On
            RewriteCond %{REQUEST_URI}  ^/socket.io            [NC]
            RewriteCond %{QUERY_STRING} transport=websocket    [NC]
            RewriteRule /(.*)           ws://localhost:8080/$1 [P,L]

            ProxyPass        /socket.io http://localhost:8080/socket.io
            ProxyPassReverse /socket.io http://localhost:8080/socket.io

            <Location />
                ProxyPass http://127.0.0.1:8080/
                ProxyPassReverse http://127.0.0.1:8080/
            </Location>
            #ProxyPass / http://localhost:8080/
            #ProxyPassReverse / http://localhost:8080/

            # BrowserMatch "MSIE [2-6]" \
            #               nokeepalive ssl-unclean-shutdown \
            #               downgrade-1.0 force-response-1.0

            BrowserMatch "MSIE [2-6]" \
                           nokeepalive ssl-unclean-shutdown \
                           downgrade-1.0 force-response-1.0

    </VirtualHost>

I have also tried changing the RewriteRule /(.*) to wss://localhost:8080/$1 [P,L] but still thrown the same error. Can't seem to find any other answer to solve this.

I believe I am using socket.io 2.0, and on the client side it is connected as such:

var socket = io();

This is what bugs me,

enter image description here

It seems that some of the connection is going through but one is not.

Upvotes: 2

Views: 16712

Answers (3)

Maka
Maka

Reputation: 663

What I have could be slightly different and I've found that some solutions don't apply in every situation. Here is what I have with Apache as reverse proxy and works for me (with https).

Server: server.js

 const express = require('express');
 const app = express();
 const http = require("http").createServer(app);
 socketio = require("socket.io")(http);
 
 const socket_port = 5003;

 // @ Start server
 http.listen(socket_port , () => console.log('Socket server served on port: ' + socket_port)); 

Apache config below.

Add ProxyPass and websocket upgrade as below. Include it at the bottom of your virtualhost configuration.

<VirtualHost *:443>


    # ... 
    # ...
    
    # Add at the end of conf
    ProxyPass / http://localhost:5003/
    RewriteEngine on
    RewriteCond %{HTTP:Upgrade} =websocket
    RewriteRule /(.*) http://localhost:5003/$1 [P,L]
    RewriteCond %{HTTP:Upgrade} !=websocket
    RewriteRule /(.*) http://localhost:5003/$1 [P,L]

</VirtualHost>

Client client.js

Connect from NodeJS client application. Supports other clients like Flutter app etc.

 var ios = require('socket.io-client');

 const externalServerAdress = "https://YOUR-DOMAIN-HERE";
 var socketClient = ios.connect(externalServerAdress, {
    reconnect: true,
    secure: true,
    rejectUnauthorized : false,
 });

 socketClient.on('connect', function (socket) {
    console.log('This client is connected to ' + externalServerAdress + ' 
 server with ID: ' + socketClient.id);
    
    // your rest of awesome code here
  
 });
  
    

Setup for HTTPS

Follow this thread where I described how ti implement it with https and Apache proxy upgrade. https://github.com/rikulo/socket.io-client-dart/issues/319

Upvotes: 0

Using Apache 2.4.6 on Centos 7

You need to do two things, first, on client-side initiate the socket-io in the following way:

var socket_io = io(wss://YOUR-IP/,{
        path: '/monitor-01',
        transports: ['websocket']
    });

Then, on the apache side, you must do the following configuration:

<VirtualHost *:443>
    .
    .
    .
    ProxyPass /monitor-01 ws://localhost:4000/socket.io
    ProxyPassReverse /monitor-01 ws://localhost:4000/socket.io
</VirtualHost>

With these configurations you may have also, multiple socket connections on the same server, and for different applications.

Upvotes: 0

AlexSashaRegan
AlexSashaRegan

Reputation: 341

Look into setting up a connection upgrade in Apache. That's what I needed to config nginx. Also, those http requests could be socketio serving the client file.

Also look into this: http://httpd.apache.org/docs/2.4/mod/mod_proxy_wstunnel.html

Edit:

The issue was solved with passing the ws/wss proxy as stated in mod_proxy_wstunnel. The apache virtual host config should have this:

         ProxyPass /socket.io/ ws://localhost:8080/socket.io
         ProxyPassReverse /socket.io/ ws://localhost:8080/socket.io

Instead of this:

        ProxyPass /socket.io http://localhost:8080/socket.io
        ProxyPassReverse /socket.io http://localhost:8080/socket.io

Upvotes: 10

Related Questions