2

I'm having a problem configuring nginx and node to support socket.io over SSL.

My nginx config:

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

server {
    listen 80;
    listen 443 ssl;
    listen [::]:80;
    listen [::]:443 ssl;

    access_log /var/log/nginx/livetest.log;
    server_name live-test.dev www.live-test.dev;

    ssl_certificate /etc/nginx/ssl/nginx.crt;
    ssl_certificate_key /etc/nginx/ssl/nginx.key;
    ssl_session_cache shared:SSL:50m;
    ssl_session_timeout 5m;

    if ($ssl_protocol = "") {
        rewrite ^ https://$host$request_uri? permanent;
    }

    location / {
        proxy_pass https://live_test;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
    }
}

live_test is upstream for node.js running on port 6020. When testing in chrome it does stop on polling with (failed) status. When using wscat:

wscat --connect wss://live-test.dev

I receive: error: Error: self signed certificate

I'm wondering what may be wrong here? Here is my node.js app:

var express = require('express');
var cookie = require('cookie');
var app = express();
var http = require('http').Server(app);
var socketIo = require('socket.io');
var redis = require('redis');
var redisClient = client = redis.createClient();

io.on('connection', function(socket){
    var cookies = cookie.parse(socket.handshake.headers.cookie);

    console.log(cookies);
});

http.listen(6020, function(){
    console.log('listening on 6020');
});

I have a feeling I'm missing something in my node.js app. I thought that since nginx handle SSL node.js does not have to anymore, but perhaps I'm mistaken.

And yes, I'm using self-signed certificate for SSL. Will node.js / socket.io work with self-signed cert?

@UPDATE

Following some reading I changed my node.js app:

var express = require('express');
var cookie = require('cookie');
var fs = require('fs');
var app = express();
var https = require('https').Server(app, {
    key: fs.readFileSync('/etc/nginx/ssl/nginx.key'),
        cert: fs.readFileSync('/etc/nginx/ssl/nginx.crt'),  
});
var socketIo = require('socket.io');
var redis = require('redis');
var redisClient = client = redis.createClient();

var io = new socketIo(https);

io.on('connection', function(socket){
    var cookies = cookie.parse(socket.handshake.headers.cookie);

    console.log(cookies);
});

https.listen(6020, function(){
    console.log('listening on 6020');
});

@UPDATE2

Following the comment by abcdn I did try wscat with -n flag, now getting error: error: Error: unexpected server response (502)

while nginx error.log contains: 2017/03/07 13:44:10 [error] 10556#10556: *140 upstream prematurely closed connection while reading response header from upstream

@UPDATE 3

After further reading, I turned my app.js back to http.

Community
  • 1
  • 1
pzaj
  • 1,062
  • 1
  • 17
  • 37
  • 1
    Did you try to `wscat -n`, i.e. `wscat --no-check` - skip certificate testing? – abcdn Mar 07 '17 at 13:38
  • @abcdn I did try it just a minute ago, updated my question – pzaj Mar 07 '17 at 13:42
  • @abcdn I believe this means nginx correctly handle the request and it's node that fails? – pzaj Mar 07 '17 at 13:53
  • 1
    Yes, I think that means exactly what you said. I am also not sure if you need to use `https` twice, if live_test is is running on the same machine. What for? You just need to use `https` between Nginx and the outside world. I am not a network topology specialist, but it seems to me that the traffic between Nginx and the local port of node.js circulates locally only. – abcdn Mar 07 '17 at 16:25
  • @abcdn You are right. I did go back to http version. Even more, I managed to find the issue. It was due to using subdomain in my actual code - browser was blocking it until I went directly to the URL and opened the unsecure connection. When switched to single domain it works just fine! Thank you for the help :) – pzaj Mar 07 '17 at 17:46
  • Ok, glad you figured it out. – abcdn Mar 07 '17 at 19:50
  • @user1970395 I am stuck with same issue and trying to fix this. Were you able to access socket.io client with http node server or did you finally change your server code to https ? I am using http server and https nignix reverse proxy, but socket.io client is not getting connected – Abhishek Kumar Aug 02 '17 at 14:23
  • @AbhishekKumar I do have regular http node.js server running behind https nginx. Please post a question with your nginx config (maybe you're missing something there?) and description of "not getting connected" error. – pzaj Aug 02 '17 at 17:29
  • Here is my question with all details https://stackoverflow.com/questions/45467169/nginx-socket-io-ssl-giving-io-is-not-defined-error – Abhishek Kumar Aug 02 '17 at 17:49

1 Answers1

1

var fs = require( 'fs' );
var app = require('express')();
var https        = require('https');
var io = require('socket.io')(https);
var HTTPSOptions = {
    cert: fs.readFileSync('path to ssl certificate file'),
    key: fs.readFileSync('path to ssl key file'),
    requestCert: false,
    rejectUnauthorized: false,
};
HTTPSOptions.agent = new https.Agent(HTTPSOptions);
var httpsServer = https.createServer(HTTPSOptions, app);
io = io.listen(httpsServer, {
    log: false
});

//io.sockets.on('connection', function (sock) {
//    console.log("CONNECTED");
//});

var Redis = require('ioredis');
var redis = new Redis();

redis.psubscribe('*', function () {});

redis.on('pmessage', function (subscribed, channel, message) {
    console.log("channel: " + channel);
    console.log("message: " + message);
    message = JSON.parse(message);
    io.emit(channel + ':' + message.event, message.data);
});

httpsServer.listen(6001, function(){
    console.log('Listening on Port 6001');
});

I spent 3 days to find a solution for this and this is my final version that works perfectly. I hope it helps anyone that got stuck like me :)

Nabil Laarif
  • 125
  • 1
  • 1
  • 7
  • Yes, you have "~" in last line, I think that's the cause. This is very nice of you posting your solution here. I did actually let nginx handle all SSL related stuff which it was handling for another app anyway. But let's hope someone will encounter this question and find your answer working! – pzaj Jun 26 '17 at 15:21