How to use the optional hostname parameter in Node.js server.listen()

22,653

So, you need a resolvable DNS host name for this to work. For a quick example, I edited the /etc/hosts file to include the following entry:

...
127.0.0.1 MyTestDnsHostName.local

then I flushed the resolver cache with the good old dscacheutil -flushcache and used the following bit of code in a simple Node.js server.

var http = require('http')
  , PORT = 8080;

function handleRequest( request, response ){
    response.end( 'It Works!' );
}

var server = http.createServer( handleRequest );

server.listen( PORT, "MyTestDnsHostName.local", 34, function(){
    console.log( "Server listening on port:%s", PORT );
});

And sure enough it works.

The error EADDRNOTAVAIL means that it's resolvable but not available; now, to be able to bind to it, it should be bindable (available) as well.

You can do a lsof -i TCP to check where it's binded.

However, I don't see why you have to bind the server elsewhere; binding to the loopback is the best practice.


Yeah, so it's actually a security flaw; if you bind it to all available interfaces 0.0.0.0, what you're essentially saying is that Listen to every available network interface there is. This may pose a security vulnerebility as it may bind to adapters you don't want it on; I've had first-hand experience of this while deploying a RoR application.

The 0.0.0.0/0 subnet is a very fancy way of saying: these are all the network interfaces I have on this computer, whilst 127.0.0.1 is ALWAYS the local-only interface. If you bind it to this, you get rid of quite a few security problems. One of which can be that the "hacker" tries to attach a listener on all interfaces, and if you don't have a very strict firewall, somewhere or the other, a leak may be present.

This is not a rule as such, but just a best practice.

P.S.: The code is a snippet I pulled off from Modulus' blog; it's quick if I want to try something out.

Share:
22,653
Yibo Yang
Author by

Yibo Yang

Updated on September 05, 2020

Comments

  • Yibo Yang
    Yibo Yang over 3 years

    From what I've read in tutorials so far, the optional hostname parameter to server.listen(port[, hostname][, backlog][, callback]) has always been either 127.0.0.1 (loopback), 0.0.0.0 (listen on every available network interface, the default option), or one of the actual IP addresses available to the server. Everything else will give an Error: listen EADDRNOTAVAIL. Is that the whole picture? (I believe hostname is technically different from IP...)

    I wasn't able to find out too much about it from the doc...

  • Yibo Yang
    Yibo Yang over 8 years
    could u provide support for "binding to the loopback is the best practice"? I thought the default all-catching 0.0.0.0 is the way to go... I'm curious as to when/why to bind the server elsewhere, hence the question :)
  • Chanoch
    Chanoch over 5 years
    I'm not sure binding to the loop back is going to work except in development but you should want to specify the interface you want to bind to ideally. As far as I am aware, the optional second parameter is actually host rather than hostname. You can provide a hostname in which case the server will attempt to look up the IP associated with that address or you can specify the address. You can also specify a unix socket (which has a file path).
  • Chanoch
    Chanoch over 5 years
    One modern reason for wanting to bind to a specific address is where you are using containers. The container might be joined to multiple networks - management and inter-container communications. You may want to ensure that a particular API server is only bound to the network over which it will accept communication as another layer of security as well as TLS, client certs/tokens, and IP based whitelisting.
  • Chanoch
    Chanoch over 5 years
    One last point, the documentation is not very helpful but the link to wikipedia has some helpful information about how 0.0.0.0/::: work which can add some information to weirdpanda's answer.