19

I've followed this tutorial to get Node.js working through Nginx on a two Ubuntu 14.04 servers via private networking (Node.js is on myappserver - accessible via private IP myprivatewebserver and publicly via mypublicappserver - and Nginx on mywebserver). Everything works fine til this point - I can access a node.js application on myprivateappserver:3000 proxied via Nginx by going to http://mywebserver/node.

However, when I try and run up the chat application in socket.io on express.js, it works when I access it directly (http://mypublicappserver:3000) but, when I try and access it via my Nginx proxy (http://mywebserver/node), I get "Cannot GET /node" in the browser and in the firebug console " "NetworkError: 404 Not Found - http://mywebserver/node".

If I curl http://myprivateappserver:3000 from mywebserver, I get index.html from my socket.io application fine.

My /etc/nginx/sites-available/default contains:

location /node{
proxy_pass http://myprivateappserver:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}

My index.js is:

var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);

app.get('/', function(req, res){
  res.sendFile(__dirname + '/index.html');
});

io.on('connection', function(socket){
  console.log('a user connected');
  socket.on('disconnect', function(){
    console.log('user disconnected');
  });
  socket.on('chat message', function(msg){
    io.emit('chat message', msg);
  });
});

http.listen(3000, function(){
  console.log('listening on *:3000');
});

and my index.html is:

<!doctype html>
<html>
  <head>
    <title>Socket.IO chat</title>
    <style>
      * { margin: 0; padding: 0; box-sizing: border-box; }
      body { font: 13px Helvetica, Arial; }
      form { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
      form input { border: 0; padding: 10px; width: 90%; margin-right: .5%; }
      form button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
      #messages { list-style-type: none; margin: 0; padding: 0; }
      #messages li { padding: 5px 10px; }
      #messages li:nth-child(odd) { background: #eee; }
    </style>
  </head>
  <body>
    <ul id="messages"></ul>
    <form action="">
      <input id="m" autocomplete="off" /><button>Send</button>
    </form>
    <script src="/socket.io/socket.io.js"></script>
    <script src="http://code.jquery.com/jquery-1.11.1.js"></script>
    <script>
      var socket = io();
      $('form').submit(function(){
        socket.emit('chat message', $('#m').val());
        $('#m').val('');
        return false;
      });
      socket.on('chat message', function(msg){
        $('#messages').append($('<li>').text(msg));
      });
    </script>
  </body>
</html>

This is my first foray into nginx/node/express/socket (I'm normally an Apache/CakePHP person) so I may well be missing something very simple but would also be very grateful for any pointers on how to debug what's going wrong

4 Answers 4

28

This is because SocketIO uses /socket.io path by default, so you need to configure Nginx so that it will proxy not only /node request, but /socket.io too:

location ~ ^/(node|socket\.io) {
    #your proxy directives
}

(By the way, it looks like you have typos: you wrote proxypass, but the correct form is proxy_pass. The same goes to other proxy directives)

You also need to perform one more edit in your NodeJS server file. Replace:

app.get('/', function(req, res){

with:

app.get('/node', function(req, res){

Now it should work.

This is not the only solution. You could also change SocketIO path with some changes in Nginx config, but the solution described above seems the simlest to me. Good luck!

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

7 Comments

Thanks so much @Curious. That would have taken me a long, long time to work out for myself - I hadn't understood how interlinked the proxied address was with the app it was proxying to. I've reinserted the underscores that were somehow removed from the proxy_pass, etc. directives when I pasted them in so as not to confuse others who arrive on this page. Thanks again.
@theotherdy you're welcome) there are various options of how to transform URL when proxying, you can read more here. What about underscores - you've done a good thing but you've missed underscore in$httpupgrade variable. Good luck:)
I think I need to do some Nginx manual reading. Well spotted on that missing underscore - now added that one as well. Thanks again
In case anyone else follows this thread, what I have just spent most of the morning realising is that when, in my CakePHP application, which is being served from mywebserver, I try and set up a connection with: var socket = io('mywebserver/node'); this is proxied correctly and connects through to mypublicappserver:3000 BUT, although the connection is there, Socket.io thinks that I am saying that I want communication to be in the 'node' namespace so emits don't work! However change to: var nsp=io.of('/node') then nsp.on('connection', function(socket){etc. and it works!
Please help me as well.. I don't want get request to pass to my app. stackoverflow.com/questions/39574238/…
|
3

Good aswer by Curious. I want to add that you don't have to adjust the node.js application if you use sub_filter. Your nginx must have been compiled with that module.

location ~ ^/(node|socket\.io) {
    #your proxy directives
    sub_filter /node /;
}

Comments

3

I think it will better if that:

location /node{
proxy_pass http://myprivateappserver:3000/; # add "/"
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}

the proxy_pass add '/', then app.get('/') is alse ok!

1 Comment

Finally! Thank you very much, finally get it working... i just add this and disabled proxy checkmark in plesk: location ~ / { proxy_pass localhost:5000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; }
-1

location ~ /(node|socket.io)  {
.......

}

This works also without " ^ " and " \ " signs.

Comments

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.