如何配置Socket.io在https上的同一端口上运行?

时间:2014-06-16 05:37:20

标签: javascript node.js sockets https socket.io

一如既往,我一直在搜索我的手指血腥找到我的问题的答案,所以我再次向所有天才伸出手! :)

我已经使用socket.io(使用express)设置了一个Node.js服务器,它使用端口8443运行良好。它运行:)。由于我的许多客户似乎不允许端口8443上的流量,因此他们无法使用我的服务。

我想知道如何在端口443上设置Node.js ,因为使用Node-server的站点已经在使用此端口(Https)。如果我尝试在我的节点服务器上使用端口443,我会得到: warn - 出错:错误:听EACCES

我的Node-js代码的一部分:

var fs = require('fs');
var https = require('https');
var express = require('express');
var socket = require('socket.io');
var port = 8443;

var sslOptions = {
  pfx: fs.readFileSync('mykey.pfx'),
     passphrase: ********
};

var app = express();

app.all('/*', function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
  res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With, *');
  next();
});

var server = https.createServer(sslOptions, app);

var io = socket.listen(server, {
    "log level" : 1,
    "match origin protocol" : true,
    "transports" : ['websocket', 'flashsocket'
   , 'xhr-polling'
   , 'jsonp-polling']
});

//No need to list all my socket events I guess

server.listen(port);

连接到我的节点服务器的客户端代码:

var socket = io.connect("https://www.*MYWEBSITE*.com", { secure: true, port: 8443});

3 个答案:

答案 0 :(得分:5)

我想你在这里问过几个不同的问题。我会自己回答它的第一个,它应该可以解决你原来的问题,但是其他一些人提出了一些值得了解的方便的部署选项。

首先,您不需要在其自己的端口上运行socket.io服务器。您可以让socket.io服务器将自己绑定到Express应用程序。例如:

// ... require stuff
var app = express();

// ... set up your express middleware, etc

var server = https.createServer(sslOptions, app);
// attach your socket.io server to the express server
var io = require("socket.io").listen(server);
server.listen(port);

无论您如何设置节点应用程序,都值得了解如何将nginx设置为反向代理。这很好,因为你不必是root用户端口< 1024运行节点应用程序时,您可以通过虚拟主机将许多应用程序绑定到同一IP地址。

这是一个nginx服务器配置块,它将反向代理节点应用程序(并支持websockets)。

server {
    listen 80;
    server_name app.com www.app.com # a list of hosts for this application
    access_log /var/log/nginx/access/app.log; # you'll need to create /var/log/nginx/access
    error_log  /var/log/nginx/error/app.log; # and you'll need to create /var/log/nginx/error

    # prevents 502 bad gateway error
    large_client_header_buffers 8 32k;

    location / {

        proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;

        proxy_set_header Accept-Encoding "";
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-NginX-Proxy true;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;

        proxy_buffers 8 32k;
        proxy_buffer_size 64k;

        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_pass http://127.0.0.1:8000; # put the port of your node app here
        proxy_redirect off;
    }
}

答案 1 :(得分:2)

您得到Error: listen EACCES因为您不能将“特权端口”(端口< 1024)用作非root用户。您可以以root用户身份运行节点进程,但不要这样做。最好让nginx(经过测试)处理HTTPS并为您代理。

查看一些信息http://nginx.com/blog/websocket-nginx/

答案 2 :(得分:2)

如上所述:

  1. 您不能将两个服务绑定到同一个端口。如果IIS(或apache或其他)正在侦听端口443,则必须先将其关闭。

  2. socket.io和你的应用程序在同一个端口上侦听。

  3. 如果要绑定到编号较小的端口(< 1024),则需要以root用户身份启动应用程序,然后降级权限,以便以最少的权限运行。这可以使用process.setuid来完成:

  4. 这个例子是用express 4和socketio 1.0制作的:

    var debug = require('debug')('httpssetuid');
    var app = require('../app');
    var http = require('http');
    var https = require('https');
    var fs = require('fs');
    var exec = require('child_process').exec;
    var EventEmitter = require('events').EventEmitter;
    var ioServer = require('socket.io');
    
    var startupItems = [];
    startupItems.httpServerReady = false;
    startupItems.httpsServerReady = false;
    
    var ee = new EventEmitter();
    
    ee.on('ready', function(arg) {
      startupItems[arg] = true;
      if (startupItems.httpServerReady && startupItems.httpsServerReady) {
        var id = exec('id -u ' + process.env.SUDO_UID, function(error, stdout, stderr) {
          if(error || stderr) throw new Error(error || stderr);
          var uid = parseInt(stdout);
          process.setuid(uid);
          console.log('de-escalated privileges. now running as %d', uid);
          setInterval(function cb(){
            var rnd = Math.random();
            console.log('emitting update: %d', rnd);
            io.emit('update', rnd);
          }, 5000);
        });
      };
    });
    
    app.set('http_port', process.env.PORT || 80);
    app.set('https_port', process.env.HTTPS_PORT || 443);
    
    var httpServer = http.createServer(app);
    
    var opts = {
      pfx: fs.readFileSync('httpssetuid.pfx')
    };
    var httpsServer = https.createServer(opts, app);
    
    var io = new ioServer();
    
    httpServer.listen(app.get('http_port'), function(){
      console.log('httpServer listening on port %d', app.get('http_port'));
      ee.emit('ready', 'httpServerReady');
    });
    
    httpsServer.listen(app.get('https_port'), function(){
      console.log('httpsServer listening on port %d', app.get('https_port'));
      ee.emit('ready', 'httpsServerReady');
    });
    
    io.attach(httpServer);
    io.attach(httpsServer);
    
    io.on('connection', function(socket){
      console.log('socket connected: %s', socket.id);
    });
    

    如果不能选择停止IIS,最好将其配置为节点应用程序的反向代理。