David C
David C

Reputation: 2038

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

Upvotes: 1

Views: 1035

Answers (2)

Greg Dubicki
Greg Dubicki

Reputation: 6950

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.

Upvotes: 3

Shimon Tolts
Shimon Tolts

Reputation: 1692

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.

Upvotes: 1

Related Questions