2
votes

Setup-

I have three servers

1] Main Server (https://mainserver.com)

2] Admin Server (https://adminserver.com)

3] Services Server (https://servicesserver.com)

Each of these server run a node.js application. They proxy pipe their respective client angular applications which is served from AWS S3 bucket. When in browser I type https://adminserver.com I get the requested admin application.Each server has nginx reverse proxy server running in front of nodejs server. Backend database is Mongo Db.

Now I had to add push notification to my applications, for which I used socket.io. I setup a socket.io server, and shared session using express session, express-socket.io-session, between my admin server, and socket io server.I worked things out in local host and everything worked fine,I got push notifications working.

I put this socketio server on a new AWS EC2 server (https://socketioserver.com).I used Nginx as reverse proxy in front of my socketio server with ssl on port 443.

Problem-

When my admin application delivered from https://adminserver.com tried to connect using socket by GET method to https://socketserver.com/socket.io, I got the following error.

Error -


XMLHttpRequest cannot load https://socketioserver.com/socket.io/?origin=adminUser&EIO=3&transport=polling&t=LY5-WlP&sid=pUXYOAj2SDammWEQAAAA. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://adminserver.com' is therefore not allowed access. The response had HTTP status code 502.


Reference

nginx code -

server {

                    listen                  443 ssl;

                    #################################
                    # SSL key and certificate paths
                    #################################

                    ssl_certificate         /home/ubuntu/ssl/server-cert.pem;
                    ssl_certificate_key     /home/ubuntu/ssl/server-key.pem;

                    #################################
                    # SSL protocol
                    #################################

                    ssl_protocols           SSLv3 TLSv1;
                    ssl_ciphers             HIGH:!aNULL:!MD5;


                    server_name             socketioserver.com;

                    error_page              502 /errors/502.html;

                    location / {

                            proxy_set_header                Upgrade             $http_upgrade;
                            proxy_set_header                Connection          "upgrade";
                            proxy_set_header                X-Forwarded-For     $proxy_add_x_forwarded_for;
                            proxy_set_header                Host                $host;
                            proxy_http_version              1.1;
                            proxy_pass                      http://project1_notification_dev_upstream;
                            proxy_redirect                  off;


                    }

    }

my socket server code -


////////////////////////////////////////////////////////////////////////////////////
/// Imports
////////////////////////////////////////////////////////////////////////////////////
var express                 = require('express');
var http                    = require('http');
var socketApp               = express();
var socketServer            = http.createServer(socketApp);
var io                      = require("socket.io")(socketServer);

var session                 = require('express-session');
var sharedSession           = require("express-socket.io-session");

var mongoose                = require('mongoose');
var mongoStore              = require('connect-mongo')(session);
var path                    = require('path');

var socketPORT              = 1367;
var requestPORT             = 2389;


var requestApp              = express();

///////////////////////////////////////////
// Configuration Files
///////////////////////////////////////////
var configMongoDb     = require(
                                  './server/configurationDetails/mongoDb/mongoDb'
                        );
var serverConfig      = require(
                                  './server/configurationDetails/server/serverConfig'
                        );



///////////////////////////////////////////////////////////////////////////////////
// Only one global variable giving th root folder of the server
///////////////////////////////////////////////////////////////////////////////////
global.serverRoot             = path.resolve(__dirname);
global.clientsGlobal          = {};
//////////////////////////////////////////////////////////////////
/// Set up Mongo Db connection
//////////////////////////////////////////////////////////////////
/// Debug Variables
/// If localDebug  = true, use local Database
/// If liveDebug   = true, use server database
/// else use main database
//////////////////////////////////////////////////////////////////
var mongoDbUrl  = "";

if( serverConfig.mode === "local" ){

  mongoDbUrl =  configMongoDb.localUrl;

}else if( serverConfig.mode === "liveDebug" ){

  mongoDbUrl =  configMongoDb.liveDebugUrl;

}else if(

          serverConfig.mode === "productionA"
          ||
          serverConfig.mode === "productionB"

        ){

  mongoDbUrl = configMongoDb.productionUrl;

}


mongoose.connect(

  mongoDbUrl,

  {
    config: {
                autoIndex: true
            }
  },

  function (err) {
    if (err) {
      console.log("error in connecting to mongo db");
      console.log(err);
    }else{
      console.log("Connected To Mongo DB");
    }
  }
);

////////////////////////////////////////////////////////////////////////////////////
var newSession = session(
                          {
                            secret            :   configMongoDb.mongoSessionSecret,
                            resave            :   false,
                            saveUninitialized :   false,
                            store             :   new mongoStore(
                                                    {
                                                      mongooseConnection : mongoose.connection
                                                    }
                                                  )
                          }

                        );
//////////////////////////////////////////////////////////////////////////////////////




requestApp.get('/userNotification',function(req,res){

  var userId = req.query.userId;
  var data   = req.query.data;

  var socketArray = clientsGlobal[userId+"_mainUser"];

  if (!Array.isArray(socketArray)) {
    return res.status(200);
  }

  for(var i = 0 ; i < socketArray.length ; i++){

    socketArray[i].emit(userId + "_mainUser" , data);

  }

  return res.status(200).send("OK");

});

requestApp.get('/adminUserNotification', function(req,res){

  var userId = req.query.userId;
  var data   = req.query.data;

  var socketArray = clientsGlobal[userId+"_adminUser"];

  if (!Array.isArray(socketArray)) {
    return res.status(200);
  }

  for(var i = 0 ; i < socketArray.length ; i++){

    socketArray[i].emit(userId + "_adminUser" , data);

  }

  return res.status(200).send("OK");

});

requestApp.get('/serviceProviderNotification',function(req,res){

  var userId = req.query.userId;
  var data   = req.query.data;

  var socketArray = clientsGlobal[userId+"_serviceProvider"];

  if (!Array.isArray(socketArray)) {
    return res.status(200);
  }

  for(var i = 0 ; i < socketArray.length ; i++){

    socketArray[i].emit(userId + "_serviceProvider" , data);

  }

  return res.status(200).send("OK");


});


var requestServer           = http.createServer(requestApp);

requestServer.listen(requestPORT , function(){

  console.log("Request Server Listening");

});




io.use(sharedSession(newSession));


io.on("connection", function(socket) {

  var origin = socket.handshake.query.origin;
  console.log(socket);
  console.log(socket.handshake.session);
  if(clientsGlobal[socket.handshake.session.passport.user+"_"+origin] === undefined){


      if(clientsGlobal[socket.handshake.session.passport.user._id+"_"+origin] === undefined){

        clientsGlobal[socket.handshake.session.passport.user._id+"_"+origin] = [];
        clientsGlobal[socket.handshake.session.passport.user._id+"_"+origin].push(socket);

      }else{

        clientsGlobal[socket.handshake.session.passport.user._id+"_"+origin].push(socket);

      }
  }

  socket.on("disconnect" , function(){


      for(var i = 0; i < clientsGlobal[socket.handshake.session.passport.user._id+"_"+origin].length ; i++ ){

        if( clientsGlobal[socket.handshake.session.passport.user._id+"_"+origin][i].id === socket.id ){

            clientsGlobal[socket.handshake.session.passport.user._id+"_"+origin].splice(i, 1);
            break;

        }

      }

      if( clientsGlobal[socket.handshake.session.passport.user._id+"_"+origin].length === 0 ){

        delete clientsGlobal[socket.handshake.session.passport.user._id+"_"+origin];

      }

  });

});


socketServer.listen(socketPORT , function(){

  console.log("socketServer running");


});
2

2 Answers

1
votes

You need to make sure your application server responds to "OPTIONS" request properly or you need to make Nginx handle the "OPTIONS" requests.

Nginx Snippet from (http://www.techniche.co/insights/how-to-install-nginx-and-setup-cors-at-amazon-ec2-instance/)

server{
 listen 80;
 server_name ;

location / {

if ($request_method = 'OPTIONS') {
    add_header 'Access-Control-Allow-Origin' '*';
    add_header 'Access-Control-Allow-Credentials' 'true';
    add_header 'Access-Control-Allow-Methods' 'GET, POST,PUT,OPTIONS';
    add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';    
    return 204;
     }
proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://localhost:3000; #(if your project is running in port 3000)
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host; 
add_header 'Access-Control-Allow-Origin' '*';
    add_header 'Access-Control-Allow-Credentials' 'true';
    add_header 'Access-Control-Allow-Methods' 'GET, POST,PUT,OPTIONS';
    add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
    }
}

You can also look at CORS Support information here - http://enable-cors.org/

0
votes

I just spent a lot of time solving a similar issues with the same setup (nginx, socket.io).

Response status 502 most likely means that nginx is not able to connect to the upstream server. You need to look into the nginx error log to find out why this is and resolve it. If nginx can't find anything upstream, it can't display origin information - and without this information, your browser doesn't want to connect. So solve the 502 error first.

In my case, the 502 error was first because nginx wasn't connecting to the correct port. In the error log nginx provides clues about where it is connecting to and what might be going wrong.

Secondly I received 502 errors because nginx didn't have the correct selinux. To fix this, you need to run:

setsebool -P httpd_can_network_relay 1

You're also going to need to set the socket origin settings. For me, this was using this code when setting up the socket:

io.set('origins', 'example1.com:* example2.com:*');