Saturday 20 May 2017

Reverse proxy websockets (socket.io) server using NGINX - 502 (Bad Gateway)

My Setup

On Ubuntu 16.04.2 LTS (Amazon AWS EC2):

My app server.js

const express = require('express');
const app = express();
const fs = require('fs');
const https = require('https');
const io = require('socket.io');
const request = require('request');

const port = 3000;

const options = {
    key: fs.readFileSync('./config/ssl/server.key'),
    cert: fs.readFileSync('./config/ssl/server.crt')
};

const httpsServer = https.createServer(options, app)
const ioServer = io(httpsServer, {
    path: '/my-app/socket.io'
});

app.set('view engine', 'ejs');
httpsServer.listen(port, function() {
    console.log("Listening on port " + port);
});

app.get('/index', function(req, res) {
    res.render(path.join(__dirname + '/views/index'));
});

app.get('/my-app/:var', function(req, res) {
   ... some code ...
}

/*
 * SocketIO server with namespace 
 */ 
var nsp = ioServer.of('my-app-sockets');

nsp.on('connection', function(socket) {
   ... more code ...
}

For the WebSocket connections, loading this Javascript in my HTML page

var mlSocket = io.connect("https://my.domain.com/my-app-sockets", {
    path: '/my-app/socket.io'
});

Where my-app-sockets is the namespace set in server.js

My NGINX configuration

worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include            mime.types;
    default_type       application/octet-stream;
    sendfile           on;
    keepalive_timeout  65;

    upstream app_server {
        server 127.0.0.1:3000;
    }

    upstream another_server {
        server www.anotherdomain.com;
    }

    # HTTPS server
    #
    server {
        listen       443 ssl;
        server_name  localhost;

        ssl_certificate      /etc/ssl/self-signed-certs/server.crt;
        ssl_certificate_key  /etc/ssl/self-signed-certs/server.key;

        ssl_session_cache    shared:SSL:1m;
        ssl_session_timeout  5m;

        ssl_ciphers  HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers  on;

        #
        # my-app
        #
        location ~ ^/(my-app|index) {
            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 https://app_server;
            proxy_redirect off;

            # WebSocket support
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
        }

        location ~ ^/(images/|javascript/|js/|css/|stylesheets/|flash/|media/|static/|robots.txt|humans.txt|favicon.ico) {
            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 https://127.0.0.1:3000;
            #proxy_pass https://app_server;
            proxy_redirect off;
        }
    }

    include servers/*;
}

502 (Bad Gateway) errors

Funny fact: I have tried both to set up NGINX on Windows 2012 Server R2 and Ubuntu 16.04 LTS. On Windows, the same NGINX configuration file looks to work fine i.e. Not having these WebSocket connection errors below

1. Failed to load resource - 502 (Bad Gateway)

From Chrome Version 58.0.3029.110 (64-bit), I can access the web app file, but I am getting error for the websocket connections

/my-app/socket.io/?EIO=3&transport=polling&t=LmdtDAK&sid=xuUsA3zdwfQ9ShiXAAAA Failed to load resource: the server responded with a status of 502 (Bad Gateway)

2. GET 502 (Bad Gateway)

universalModuleDefinition:2 POST https://my.domain.com/my-app/socket.io/?EIO=3&transport=polling&t=LmdtEPE&sid=nWZYce-aUu0oSH-mAAAA 502 (Bad Gateway)
i.create @ universalModuleDefinition:2
i @ universalModuleDefinition:2
o.request @ universalModuleDefinition:2
o.doWrite @ universalModuleDefinition:2
(anonymous) @ universalModuleDefinition:2
(anonymous) @ universalModuleDefinition:2
o @ universalModuleDefinition:2
(anonymous) @ universalModuleDefinition:2
(anonymous) @ universalModuleDefinition:2
e.encodePacket @ universalModuleDefinition:2
i @ universalModuleDefinition:2
i @ universalModuleDefinition:2
c @ universalModuleDefinition:2
e.encodePayload @ universalModuleDefinition:2
n.write @ universalModuleDefinition:2
n.send @ universalModuleDefinition:2
n.flush @ universalModuleDefinition:2
n.onDrain @ universalModuleDefinition:2
(anonymous) @ universalModuleDefinition:2
n.emit @ universalModuleDefinition:2
r @ universalModuleDefinition:2
n.emit @ universalModuleDefinition:2
i.onSuccess @ universalModuleDefinition:2
i.onData @ universalModuleDefinition:2
i.onLoad @ universalModuleDefinition:2
hasXDR.r.onreadystatechange @ universalModuleDefinition:2

3. POST 502 (Bad Gateway)

POST https://my.domain.com/my-app/socket.io/?EIO=3&transport=polling&t=LmdtEPE&sid=nWZYce-aUu0oSH-mAAAA 502 (Bad Gateway)
i.create @ universalModuleDefinition:2
i @ universalModuleDefinition:2
o.request @ universalModuleDefinition:2
o.doWrite @ universalModuleDefinition:2
(anonymous) @ universalModuleDefinition:2
(anonymous) @ universalModuleDefinition:2
o @ universalModuleDefinition:2
(anonymous) @ universalModuleDefinition:2
(anonymous) @ universalModuleDefinition:2
e.encodePacket @ universalModuleDefinition:2
i @ universalModuleDefinition:2
i @ universalModuleDefinition:2
c @ universalModuleDefinition:2
e.encodePayload @ universalModuleDefinition:2
n.write @ universalModuleDefinition:2
n.send @ universalModuleDefinition:2
n.flush @ universalModuleDefinition:2
n.onDrain @ universalModuleDefinition:2
(anonymous) @ universalModuleDefinition:2
n.emit @ universalModuleDefinition:2
r @ universalModuleDefinition:2
n.emit @ universalModuleDefinition:2
i.onSuccess @ universalModuleDefinition:2
i.onData @ universalModuleDefinition:2
i.onLoad @ universalModuleDefinition:2
hasXDR.r.onreadystatechange @ universalModuleDefinition:2

Any pointers on what I may be doing wrong?

Different articles seems to concur, that I am doing the correct thing to upgrade HTTP connections to a WebSocket and does the NGINX doc.

Part of the problem, comes certainly that I am very new to NGINX and that I also don't understand what needs to be done in NGINX to reverse proxy the WebSocket connections. May be the fact that I am using a namespace is spicing things up a little. Any help and explanation will be appreciated.



via zabumba

No comments:

Post a Comment