Socket.io not working on aws with nodejs - node.js

I am trying to connect to socket on aws ec2 instance. For some reason I am not able to do so . My client side code is :
var socket = io.connect('http://ec2-MY-IP.us-west-2.compute.amazonaws.com:3000');
console.log(socket);
socket.on('connect', function(){
alert(socket.id); // 'G5p5...
});
socket.on('connect_error', function(){
console.log('Connection Failed');
});
I Always get "Connection Failed" In browser console
I have opened the port from the security group's Inbound section and when I use :
telnet ec2-MY-IP.us-west-2.compute.amazonaws.com 3000
It gives me output
Trying ...
Connected to ec2-MY-IP.us-west-2.compute.amazonaws.com.
Escape character is '^]'.
My server Side Code goes HERE :
const express = require('express');
const bodyParser= require('body-parser');
const app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
http.listen(3000, () => {
console.log('listening on 3000');
});
MongoClient.connect('mongodb://ec2-MY-IP.us-west-2.compute.amazonaws.com:27017/userlogsdemo', (err, database) => {
if (err) return console.log(err)
db = database;
console.log("DB CONNECTED")
io.on('connection', function (socket) {
console.log("SOCKET CONNECTED")
socketobj = socket
socket.on('reloadtickets', function (data) {
connectedusers.forEach(function(v){
if(v.connecteduserid == data.target){
setTimeout(function () {
io.emit('reloadticketsok',data );
}, 100)
}
});
});
// WHEN SOMEONE IS DISCONNECTED
});
})
When I RUN "node server.js" It says "DB CONNECTED" but not "SOCKET CONNECTED".
Code with localhost:8080(ON my local machine not on aws) works properly. Is there Anything special required to be done on aws Ec2. Any suggestions will be appreciated . Thanks in advance

There are 2 things that you can check.
How you configured your security groups. Please verify once :
You should select 'Custom TCP Rule' Port Range 3000 (as per your code), Source you can select anywhere(for testing).
You should check whether port 3000 is opened on linux(aws) firewall. To allow you can run :
sudo iptables -I INPUT -p tcp --dport 3000 -j ACCEPT
Let's take a closer look at the above command. We know what the iptables is in the command, thats the binary or program itself, now let's look at the other options.
-I stands for insert. This will insert the rule at the top of the chain. You can also use -A for append, which will place the new rule at the end of the chain.
INPUT tells the iptables command which chain you want the rule entered into.
-p tcp tells the rule to match only packets using the TCP protocol.
--dport 80 says to match traffic headed for port 80, or http. --dport stands for destination port.
-j stands for JUMP to jump to the specified action or chain. In our case we are using -j ACCEPT so it will jump to the ACCEPT action and allow the traffic through.

You should be open your port for socket on which its running
Lets you are using port 8890
sudo iptables -I INPUT -p tcp --dport 8890 -j ACCEPT

Related

Why it's create localhost:5000 CLOSE_WAIT Node?

my server started with PORT 5000, and sometimes it show next error
Error: listen EADDRINUSE: address already in use :::5000
When I Check port 5000, I see what port :5000 use for Chrome. They pass away after time( 1 min ) but, it's create more problems, i don't check code with terminal, because after error not showing console.log?
I think that chrome is launched by some development tool. Because System apps can not take port number more that 1024. So you need to check if your IDE is launching it and then check how to change the port or you can follow this link to auto increment the port if given port is not available.
var portrange = 45032
function getPort (cb) {
var port = portrange
portrange += 1
var server = net.createServer()
server.listen(port, function (err) {
server.once('close', function () {
cb(port)
})
server.close()
})
server.on('error', function (err) {
getPort(cb)
})
}
Code from link

Can't connect to Node server on Amazon EC2

Here's the app.js, the code is too long so that's why I'm showing this code only, there's no problem in other code I assume this is a network problem.
app.js
app.listen(8080, 'localhost', function () {
console.log('Express started on http://localhost:' + 8080 + '; press Ctrl-C to terminate.');
});
I don't get any response when i run lsof -i :8080. but I do get response when I run curl localhost:8080 on the server.
and I don't think there's any problem with security group. I allowed any ip to access to the instance as you can see below.
and here's actually how it looks like when I test public ip and localhost
ubuntu#:ip~/$ curl -v 18.217.107.76:8080
* Rebuilt URL to: 18.217.107.76:8080/
* Trying 18.217.107.76...
* connect to 18.217.107.76 port 8080 failed: Connection refused
* Failed to connect to 18.217.107.76 port 8080: Connection refused
* Closing connection 0
curl: (7) Failed to connect to 18.217.107.76 port 8080: Connection refused
ubuntu#ip:~/$ curl -v localhost:8080
I get response here!
I changed the code from
app.listen(8080, 'localhost', function () {
console.log('Express started on http://localhost:' + 8080 + '; press Ctrl-C to terminate.');
});
to
app.listen(8080, function () {
console.log('Express started on http://localhost:' + 8080 + '; press Ctrl-C to terminate.');
});
now it's working
This is what worked for me!!
In your security group you have added the rule HTTP which listens by default on port 80.
So basically if you have configured your node server to run on a port other than port number 80 (I was doing this mistake) and try to access the public DNS(EC2 public DNS can be found in instance description) on browser, connection refused error might come so what you can do is change the PORT value in the config to 80.
Your config.env will look like this
PORT=80
And in your server.js you can write
const PORT = process.env.PORT;
try {
app.listen(PORT, () => { console.log(`server running at port ${PORT}`) })
} catch (error) {
console.log(error)
}

Socket.io client : Websocket Connection failed : Connection closed before receiving a handshake response

I'm building an web app(nodejs, port: xxx0) which interacts with an another app(nodejs, port:xxx5) which is serving as the socket.io server. My socket.io client code goes well in my web app. All works well in my local as the connections refers to the server as io.connect('http://localhost:xxx5/')
But the same is not working when i promote it to higher env as the connection string is as io.connect('https://domainName/')
When my app is trying to connect, I'm receiving the below error:
websocket.js:112 WebSocket connection to 'wss://domainName/socket.io/?EIO=3&transport=websocket' failed: Connection closed before receiving a handshake response
Am I missing anything?
When I try hitting the server(higher env) via socket.io tester, I get the response as No sockets Found and immediately then An error occurred while reconnecting
NOTE:. The server instances are registered in an api gateway in higher env.
Server.js
const app = require('express')()
const port = process.env.PORT || xxx5
const server = app.listen(port)
const io = require('socket.io').listen(server)
let ns = io.of('/namespace')
ns.on('connection', (socket) => {
logger.info('User connected')
socket.emit('messages', {new:2,[{title:'Hi'},{title:'Test'}]})
})
Client.js
import io from 'socket.io-client'
const socket = io(`https://domainName/namespace`, { transports:
['websocket'], rejectUnauthorized: true})
// const socket = io('http://localhost:xxx5/namespace', { transports:
['websocket'], rejectUnauthorized: true})
// above commented url is in local
socket.on('connect', () => {
logger.info("Connected")
})
socket.on('messages', (data) => {
logger.info(`New messages : ${data.new}`)
})
socket.on('error', (error) => {
logger.error(`Error encountered : ${error}`)
})
Is your application running as a priveleged user? Any TCP/UDP socket less than 1024 is considered and IANA reserved port and required elevated priveleges to bind as a listening service.
Using cURL can also aid in providing the necessary handshake: (See reference of websocket handshake process here; https://en.m.wikipedia.org/wiki/WebSocket#Protocol_handshake)
sh
$ curl -i -N -H "Connection: Upgrade" -H "Upgrade: websocket" -H "Host: echo.websocket.org" -H "Origin: http://domainname " http://domainname

nodejs v5.10.1 cannot get my host address anymore?

Why the latest version of nodejs (v5.10.1) cannot get my host address anymore?
express code:
var express = require('express');
var app = express();
// respond with "Hello World!" on the homepage
app.get('/', function (req, res) {
res.send('Hello World!');
});
var server = app.listen(3000, function () {
var host = server.address().address;
var port = server.address().port;
console.log(server.address());
console.log('Example app listening at http://%s:%s', host, port);
});
result:
{ address: '::', family: 'IPv6', port: 3000 }
Example app listening at http://:::3000
It should be:
http://127.0.0.1
Any ideas how I can fix this?
I am on Linux.
Actually, maybe you will see something like
:80
and then
::80
actually this one have a pattern like this:
host:port IPv4
host::port IPv6
127.0.0.1:80 means that using IPv4, listening in 127.0.0.1 in port 80
:80 means that using IPv4 ,listening on all address in port 80
127.0.0.1::80 means that using IPv6, listening in 127.0.0.1 in port 80
and so on.
so, the ::3000 means listening to IPv6 in port 3000
These configuration was done under these variable
var host = server.address().address;
var port = server.address().port;
you can just change the value of these variable to "127.0.0.1" and "80" and see what happens, but most likely your machine still using IPv6 there, if you want to change to IPv4 for your machine, change the setting of your machine under:
Windows: control panel -> network and sharing center -> (your network) -> properties -> setup the IPv4
Linux: i dont have linux machine to test this, but the syntax should be using ifconfig or ipconfig depends on your linux, please refer for something like https://unix.stackexchange.com/questions/34093/static-ipv4-ipv6-configuration-on-centos-6-2
Mac: i dont have mac machine also, should be the same with linux so try to do the same also
I have the same problem, i solved it acessing like an array:
server.address()["port"]
Here a example:
export const onError = (server: Server) => {
console.log(server.address()["port"])
return (error: NodeJS.ErrnoException): void => {
let port: number | string = server.address()["port"];
if (error.syscall !== 'listen') throw error;
let bind = (typeof port === 'string') ? `pipe ${port}` : `port ${port}`;
switch(error.code) {
case 'EACCES':
console.error(`${bind} requires elevated privileges`);
process.exit(1);
break;
case 'EADDRINUSE':
console.error(`${bind} is already in use`);
process.exit(1);
break;
default:
throw error;
}
}
}

How can I make a successful http POST using node.js to an aws instance?

I am working on setting up an aws instance to listen for http POST's. When running the server and client both as local host, everything seems to work fine. However, when running trying to make a post with the client to an aws instance with the server running, I am getting a connect ECONNREFUSED error.
The aws instance (ubuntu server) that I am using has both ports 80 and 8080 open to all ip addresses. I am using the pm2 module to keep the server running. Although using pm2 is giving the same error.
Server Setup: (aws instance terminal)
$ sudo apt-get install git
$ curl -sL https://deb.nodesource.com/setup | sudo bash -
$ sudo apt-get install -y nodejs
$ sudo npm install pm2 -g --unsafe-perm
Using node to start server:
$ node nodeServerTest.js
Using pm2 to start server:
$ pm2 start nodeServerTest.js --name "nodeServerTest" -i max
Server Code:
// nodeServerTest.js
var http = require("http");
function startServer(port, ip) {
// requestListener handles incoming requests
function requestListener(request, response) {
if (request.method == 'POST') {
var body = '';
request.on('data', function (data) {
body += data;
// destroys connection if too long
if (body.length > 1e6) {
request.connection.destroy();
}
});
request.on('end', function() {
// checks for json, otherwise destroys connection
try {
var POST = JSON.parse(body);
console.log('valid post:')
console.log(POST)
response.end('post accepted');
}
catch(err) {
console.log('bad post, ending connection')
response.connection.destroy();
}
});
}
else {
response.end();
}
};
// creates the eventEmitter
var server = http.createServer(requestListener);
// beigns listening on specified port
server.listen(port, ip);
// logs when someone attempts to connect
server.on('connection', function (stream) {
console.log('someone connected!');
});
// notifies when server has started
console.log('Server running at http://'+ip+':'+port);
}
startServer(8080, '127.0.0.1');
Client Code: (I change the host field to the ip address when attempting to post to the aws instance)
// nodeClientTest.js
function httpPost() {
var http = require("http");
var postData = JSON.stringify({
'msg': 'Hello World!'
});
var options = {
host: "localhost", // using correct public ip
port: 8080,
method: 'POST',
path: '/',
headers: {
'Content-Type': 'application/json',
'Content-Length': postData.length
}
};
var req = http.request(options, function(res) {
console.log('STATUS: ' + res.statusCode);
console.log('HEADERS: ' + JSON.stringify(res.headers));
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('BODY: ' + chunk);
});
});
req.on('error', function(e) {
console.log('problem with request: ' + e.message);
});
// write data to request body
req.write(postData);
req.end();
}
httpPost();
Thank you for any help, if more information is needed please leave a comment
You are binding your server to the loopback interface here:
startServer(8080, '127.0.0.1');
..which makes is available only locally. To allow access via your eth0 interface, so from other network hosts replace this line with:
startServer(8080);
..to listen on port 8080 TCP on all interfaces, according to Node.js manual.
PS Please remember that your private IP on AWS EC2 != public IP address. You can check both by running ec2metadata command on your EC2 host.
An explanation, as OP requested:
each TCP server socket has to be bound to a specific network interface. This is because you make you connect your client TCP socket to a combination of IP:port and the IP is bound to the interface.
loopback interface with a 127.0.0.1 IP address is as special virtual interface available only from the localhost, targeting ifself (hence the name),
So when you run your server binding it to loopback the only way you could have only made the request to it would be initiating the connection from that host itself, for example with telnet like this: telnet 127.0.0.1 8080.
You could have bind the server to the actual IP of eth0 interface but this is inpractical, especially on EC2 servers where private IPs change.
That's why I proposed the simpler, universal syntax. A side effect is that this way your server listens on both loopback and eth0 but it only helps, for example when you want to separate your own, local traffic from the rest of the traffic by based on the interface used.
It seems like your server is only binding to the local address of the server (127.0.0.1) and not listening to connections outside of the server.
Please try to change the listening address of the server to 0.0.0.0
startServer(8080, '0.0.0.0');
I would also advise you to check the express web framework for your server.

Resources