2

I'm using nginx for web-facing traffic and proxying my node.js connections, as well as handling my SSL.

The connection IS successfully established--io.on('connection') does trigger a console log server side, but then I get a 400 (Bad Request) on the client (in both Firefox and Chrome) and then the connection resets over and over (and continues throwing the same error).

The error is as follows (from Chrome):

polling-xhr.js:264 GET https://192.168.56.101/socket.io/?EIO=3&transport=polling&t=M54C3iW&sid=byqOIkctI9uWOAU2AAAA 400 (Bad Request)
    i.create @ polling-xhr.js:264
    i @ polling-xhr.js:165
    o.request @ polling-xhr.js:92
    o.doPoll @ polling-xhr.js:122
    n.poll @ polling.js:118
    n.onData @ polling.js:157
    (anonymous) @ polling-xhr.js:125
    n.emit @ index.js:133
    i.onData @ polling-xhr.js:299
    i.onLoad @ polling-xhr.js:366
    hasXDR.r.onreadystatechange @ polling-xhr.js:252
    XMLHttpRequest.send (async)
    i.create @ polling-xhr.js:264
    i @ polling-xhr.js:165
    o.request @ polling-xhr.js:92
    o.doPoll @ polling-xhr.js:122
    n.poll @ polling.js:118
    n.doOpen @ polling.js:63
    n.open @ transport.js:80
    n.open @ socket.js:245
    n @ socket.js:119
    n @ socket.js:28
    n.open.n.connect @ manager.js:226
    n @ manager.js:69
    n @ manager.js:37
    n @ index.js:60
    (anonymous) @ control.js:6
192.168.56.101/:1 WebSocket connection to 'wss://192.168.56.101/socket.io/?EIO=3&transport=websocket&sid=byqOIkctI9uWOAU2AAAA' failed: WebSocket is closed before the connection is established.

Nginx logs (at info level) show the following:

2018/01/29 19:37:10 [info] 28262#28262: *18403 client closed connection while waiting for request, client: 192.168.56.1, server: 192.168.56.101:443

My nginx config is as follows (I HAVE tried this both with and without the "location /socket.io/ " block, and get exactly the same results.):

map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}
upstream altairServer {
    server 192.168.56.101:8000;
}
server {
    listen 192.168.56.101:443;
    server_name     altair.e6diaspora.com;

    ssl on;
    ssl_certificate /home/e6serv/crypto/domain.pem;
    ssl_certificate_key /home/e6serv/crypto/server.key;

    access_log /home/e6serv/logs/nginx/host.access.log;
    error_log /home/e6serv/logs/nginx/host.error.log;

    root        /home/e6serv/e6Code/e6GS1/public;

    location / {
            try_files maintain.html $uri $uri/index.html @node;
    }

    location /socket.io/ {
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $http_host;
            proxy_set_header X-NginX-Proxy true;

            proxy_pass http://altairServer;
            proxy_redirect off;

            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
    }

    location @node {
            proxy_pass http://altairServer;
            proxy_http_version 1.1;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header Host $host;
            proxy_set_header X-NginX-Proxy true;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "Upgrade";
            proxy_max_temp_file_size 0;
            proxy_redirect off;
            proxy_read_timeout 240s;
    }
}

The relevant server side code is as follows:

const app = express();
app.set('port', 8000);
app.engine('html', require('ejs').renderFile);
app.use(methodOverride());
app.use(session({
secret: SITE_SECRET,
    store: redisSesStore,
    cookie: {maxAge: 604800000},
    resave: false,
    saveUninitialized: false
}));
app.use(parseCookie());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use('/',router);

const httpServer = http.createServer(app)
const io = socketIo.listen(httpServer);

io.use(passportSocketIo.authorize({
    key: 'connect.sid',
    secret: SITE_SECRET,
    store: redisSesStore,
    passport: passport,
    cookieParser: parseCookie
}));

httpServer.listen(app.get('port'), '192.168.56.101', function(){
    log.warn('Worker Started HTTP Server')
});

io.on('connection', function(socket) {
    log.debug(socket.request.user)
    var event = { type:'userConnect',data:'Hello Client'};
    process.send(event);
}

My client side code is as follows:

control.socket = io.connect('https://'+hostname);
console.log("Should be connected")
//NOTE: This final line does not work--the console.log never fires:
control.socket.on('userConnect',function (data) {console.log(data)}) 
2
  • Also note: my server side code should have socket.emit instead of process.send on the last line. (This added to my confusion substantially.) Commented Jan 30, 2018 at 7:01
  • 1
    no reason for: proxy_set_header X-NginX-Proxy true; Commented Sep 23, 2020 at 13:17

1 Answer 1

3

I've discovered the source of the problem... The extra element that was in here that I didn't know to talk about was node.js's Cluster.

https://github.com/socketio/socket.io/issues/1942

https://socket.io/docs/using-multiple-nodes/

Socket.io defaults to polling, which requires a sticky load balancing between the various workers. The solution was as found in the socket.io multiple node documentation.

I added something like the following to my nginx config:

upstream io_nodes {
    ip_hash;
    server 127.0.0.1:6001;
    server 127.0.0.1:6002;
    server 127.0.0.1:6003;
    server 127.0.0.1:6004;
}

(Also note, specific workers must be set up to listen on specific ports.)

Sign up to request clarification or add additional context in comments.

2 Comments

So, what about an application balancer on the AWS ECS Clusters? I have the same problem. I added two instances of the containers on the task definition and added a load balancer to connect them to the cluster. But the (400 Bad request occurred).
@Shahab.es - I haven't used AWS, so I can't tell you specifically. Try looking up sticky load balancing for whatever load balancer you're using and see if it has something in their documentation. Wish I could help more.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.