MacOS – Why can’t browsers resolve localhost

macosweb-browserwebserver

I've got a program on my machine listening on port 8080 to respond to HTTP requests. But when I try to go to http://localhost:8080/ in a browser…

Chrome says:

The localhost page isn’t working

localhost didn’t send any data. ERR_EMPTY_RESPONSE

Firefox redirects the request to www.localhost.com:8080 which of course isn't correct. My research suggests that it is doing this because it can't find localhost.

Safari says it can't open the page because "the server unexpectedly dropped the connection."

However, if I go to http://127.0.0.1:8080 the page loads correctly.

Therefore, it would seem that for some reason OS X isn't properly resolving localhost to 127.0.0.1. If I try to ping localhost from the command line, it works, but my understanding is that name resolution works differently in different places.

I have read various issues where localhost doesn't resolve e.g. from ping, but I am not having that problem. All the cases where localhost were not working in the browser appear to not have solutions related to the actual problem I am having. I have also seen places where people have mentioned that localhost does work in the browser, so I am wondering what I am doing wrong here.

From comments
If I try the IPv6 address for localhost http://[::1]:8080/ then I get the same errors as using localhost.

Best Answer

First check name resolution with the system resolver:

dscacheutil -q host -a name localhost

If you get an output like:

name: localhost
ipv6_address: ::1

name: localhost
ip_address: 127.0.0.1

the system resolver works correctly.

Stop your node.js app, create a simple node.js server by using this file with an arbitrary name (e.g. multiserver.js):

var http = require('http');
function handler(req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
};
http.createServer(handler).listen(3000, '127.0.0.1');
http.createServer(handler).listen(3001, 'localhost');
http.createServer(handler).listen(3002, '192.168.0.5');
http.createServer(handler).listen(3003, 'host.example.com');
http.createServer(handler).listen(3004, 'LocalHostName.local');

(replace the IP of the :3002 server by an IP of your host (ifconfig), the host.example.com of the :3003 server by the output of echo $HOSTNAME and LocalHostName by the output of scutil --get LocalHostName)

and start it with

node ../multiserver.js

Now test your "multiserver" with Google Chrome by entering http://name:port (don't forget to prepend http://).

The first two ports should work with both "names" (127.0.0.1/localhost). So entering either http://127.0.0.1:3000, http://127.0.0.1:3001, http://localhost:3000 or http://localhost:3001 should all yield "Hello World".

Also check the nine permutations of the next three ports and names (e.g. http://LocalHostName.local:3002 or http://192.168.0.5:3004) which should also all yield "Hello World" if the hostname/DNS are set up correctly.

If all this works, your express/node.js app is faulty.