4

I was trying to introduce socket.io to my application developed in Laravel and in AngularJS.
The application works fine in my computer, nevertheless when I try to make it work on the server I get the error 'GET http://localhost:8080/socket.io/?EIO=3&transport=polling&t=LQxpNjO net::ERR_CONNECTION_REFUSED'.

The server is running Ubuntu 16.04 and I am using nginx as a web server.

This is the file which creates the nodejs server:

var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var Redis = require('ioredis');
var redis = new Redis();

var port = 8080;

http.listen(port, function() {
  console.log('Listening on *:' + port);
});

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

  console.info('Client connected');

  redis.subscribe('counter.increase');

  redis.on('message', function (channel, message) {
    console.log('Received message ' + message + ' in channel ' + channel);

    socket.emit(channel, message);
  });

  socket.on('disconnect', function() {
    console.info('Client disconnected');
  });

});

This is the AngularJS factory that should connect to the nodejs server. Here I am using angular-socket-io:

angular.module('myServices').factory('socket', function (socketFactory) {
  var ioSocket = io.connect('http://localhost:8080');

  socket = socketFactory({
    ioSocket: ioSocket
  });

  return socket;
});

This is the configuration file of nginx (/etc/nginx/sites-available/default):

server {
    listen 80 default_server;
    listen [::]:80 default_server;

    root /var/www/html/public;
    index index.php index.html index.htm index.nginx-debian.html;

    server_name XXX.XXX.XXX.XXX;

    location / {
        try_files $uri $uri/ /index.php;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php7.0-fpm.sock;
    }

    location ~ /\.ht {
        deny all;
    }
}

How could I solve this problem?


Update 1

I updated the nginx configuration file like this:

server {
    listen 80 default_server;
    listen [::]:80 default_server;

    root /var/www/html/public;

    index index.php index.html index.htm index.nginx-debian.html;
    server_name XXX.XXX.XXX.XXX;
    location / {
        try_files $uri $uri/ /index.php;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php7.0-fpm.sock;
    }

    location ~* \.io {
        proxy_pass http://localhost:8080;
        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;
    }

    location ~ /\.ht {
        deny all;
    }
}

upstream app_yourdomain {
    server 127.0.0.1:3000;
    keepalive 8;
}

and the AngularJS factory like this:

angular.module('myServices').factory('socket', function (socketFactory) {
  var ioSocket = io.connect('http://localhost:8080/socket.io');

  socket = socketFactory({
    ioSocket: ioSocket
  });

  return socket;
});

Now i get the following error:
- GET http://example.com/bower_components/socket.io-client/socket.io.js


Update 2

These are my nginx configuration file:

upstream app_example.com {
    server 127.0.0.1:3000;
    keepalive 8;
}

server {
    listen 80 default_server;
    listen [::]:80 default_server;

    root /var/www/html/public;

    index index.php index.html index.htm index.nginx-debian.html;

    server_name XXX.XXX.XXX.XXX;

    location / {
        # First attempt to serve request as file, then as
        # directory, then fall back to displaying a 404.
        try_files $uri $uri/ /index.php;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php7.0-fpm.sock;
    }

    location ~ ^/(socket\.io) {
        proxy_pass http://localhost:8080;
        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;
    }

    location ~ /\.ht {
        deny all;
    }
}

and the AngularJS factory:

angular.module('myServices').factory('socket', function (socketFactory) {
  var ioSocket = io.connect('http://localhost');

  socket = socketFactory({
    ioSocket: ioSocket
  });

  return socket;
});




Working solution

Thanks to John I finally managed to make the application work.

This is nginx configuration file:

upstream app_example.com {
    server 127.0.0.1:3000;
    keepalive 8;
}

server {
    listen 80 default_server;
    listen [::]:80 default_server;

    root /var/www/html/public;

    index index.php index.html index.htm index.nginx-debian.html;

    server_name XXX.XXX.XXX.XXX;
    location / {
        try_files $uri $uri/ /index.php;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php7.0-fpm.sock;
    }

    location ~ ^/(socket\.io) {
        proxy_pass http://localhost: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;
    }

    location ~ /\.ht {
        deny all;
    }
}

This is the AngularJS factory:

angular.module('myServices').factory('socket', function (socketFactory) {
  var ioSocket = io.connect('http://example.com');

  socket = socketFactory({
    ioSocket: ioSocket
  });

  return socket;
});

This is the nodejs server:

var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var Redis = require('ioredis');
var redis = new Redis();

var port = 3000;

http.listen(port, function() {
  console.log('Listening on *:' + port);
});

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

  console.info('Client connected');

  redis.subscribe('counter.increase');

  redis.on('message', function (channel, message) {
    console.log('Received message ' + message + ' in channel ' + channel);

    socket.emit(channel, message);
  });

  socket.on('disconnect', function() {
    console.info('Client disconnected');
  });

});
Alex Miccio
  • 43
  • 1
  • 6

3 Answers3

5

Socket.io use /socket.io after your domaine name. Then you have to specify the socket.io location :

location ~* \.io {
    proxy_pass http://localhost:8080;
    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;        
}

And don't forget the upstream for your node js app

upstream app_yourdomain {
    server 127.0.0.1:3000;
    keepalive 8;
}
John
  • 4,711
  • 9
  • 51
  • 101
  • I updated the answer. Maybe I did not understand where I have to specify the socket.io location? – Alex Miccio Aug 24 '16 at 13:18
  • Yes it's ok. You can try `location ~ ^/(socket\.io) {` too. But with the proxy pass you don't have to specify the port when you go to your website. `http://localhost` should be work. Have you set the upstream above `server {` ? – John Aug 24 '16 at 13:35
  • I updated the answer again. Now the previous error seems to ge solved, but unfortunately I get other two: GET http://localhost/socket.io/?EIO=3&transport=polling&t=LQyrolW and XMLHttpRequest cannot load http://localhost/socket.io/?EIO=3&transport=polling&t=LQyrolW. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://example.com' is therefore not allowed access. The response had HTTP status code 404. Sorry if I post the errors here but in the question I could not post more then two links. – Alex Miccio Aug 24 '16 at 14:02
  • The upstream that I show you running on the port 3000. Could you try to run your node js app on the port 3000 instead of 8080 ? – John Aug 24 '16 at 14:08
  • And inside the nginx location replace `proxy_pass http://localhost:8080;` by `proxy_pass http://localhost:3000;` – John Aug 24 '16 at 14:15
  • Thank you very very much. I finally managed to make it work. Now I will update the question with the working solution – Alex Miccio Aug 24 '16 at 14:22
  • Hi guys, I've made sure to do exactly like in the example bit I still get the same error. Kindly help. – NIMROD MAINA Jan 27 '17 at 15:04
  • Getting a `net::ERR_SSL_PROTOCOL_ERROR` now – leonheess Aug 14 '19 at 18:03
0

For anyone else who is might be trying to figure this out like me, I just got this working after 4 hours of trying on a digital ocean server.

Follow the working solution that OP edited into the answer solved half of it, however I had to use a cdn for the links inside my html files.

Here's the cdn's to choose from https://cdnjs.com/libraries/socket.io. Pick one and replace the url in <script src="http://localhost:3000/socket.io/socket.io.js"></script> with the cdn on the pages where you need it.

For my client side javascript (or angular in this case), just use the public domain name that you want to connect to the app with.

Also, make sure you add the the stuff you don't have in your nginx setup that OP wrote in the working answer. No need for the php section unless you're using php. I'm not so I omitted it. Make sure that you replace 'app_example.com' with the same address or domain that you used in your client side javascript.

This probably isn't the right place to post this but I can't comment yet and I don't want other people going through 4 hours of trial and error.

ryandougc
  • 109
  • 6
  • Usually you don't need to include socket.io from a cdn - your server would host the client side script and provide it like John said in his answer: "Socket.io use /socket.io after your domaine name". Also from the official documentation it is loaded relative to your root domain like `` - https://socket.io/get-started/chat/#Integrating-Socket-IO – kidroca May 04 '20 at 23:24
  • Nowhere the author is mentioning a `` in his html. Having the address hardcoded to `localhost:3000` would not work in production that's why a relative path is used e.g. `src="/socket.io/socket.io.js"` so it will work if the domain is `localhost:3000`, `localhost:4000` or `app.example.com` – kidroca May 04 '20 at 23:27
  • 1
    @kidroca I learned socket.io from a few youtube videos and the link was always hardcoded. It would've been nice to have the relative path, cause that works as well. Thanks for showing that, I missed it in the docs. I guess I should've made it more clear though, the post wasn't for OP, since they clearly have a solution already. It was for anyone else who was looking to figure this out and might come across this comment and didn't think to check for using the relative path. – ryandougc May 05 '20 at 00:46
0

John's answer is correct. In case someone is looking for extra info. Suggesting that your localhost is on 9000 at EC2, with React framework for front-end.

Project structure

  • your-project-folder/api/app.js
  • your-project-folder/client/src/socket.js

Client(===your-project-folder/client/src/socket.js):

import { io } from "socket.io-client"; // make sure you have npm i socket.io-client under "your-project-folder/client"
export const socket = io.connect('https://yourdomain'); // production
// Develop: export io.connect('http://localhost:9000');

You do NOT need <script src="%PUBLIC_URL%/socket.io/socket.io.js"></script> under client/public/index.html because you access socket client from import { io } from "socket.io-client"; ...which is from your node_modules under your client/ folder.

And under server/ section inside /etc/nginx/nginx.conf

# Connect to socket io server
location ~* \.io {
proxy_pass http://localhost:9000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header Connection 'upgrade';
}
shellyyg
  • 101
  • 4