Bossy Lobster

A blog by Danny Hermes; musing on tech, mathematics, etc.

Edit on GitHub

Difference Between localhost and 0.0.0.0

Note: In a docker container, a server can only be available outside of the container / pod if it is bound to the "any host" IP1. Binding a server to localhost / the loopback IP2 will mean the server is only reachable within the container / pod.

Consider the following Express application which binds to the default IP for port 3000, explicitly binds to 127.0.0.1 for port 4000 and explicitly binds to 0.0.0.0 for port 5000:

// index.js
const express = require("express");
const app = express();
app.get("/", (req, res) => res.send("Hello World!\n"));
app.listen(3000, () => console.log("Listening on port 3000"));
app.listen(4000, "127.0.0.1", () => console.log("Listening on port 4000"));
app.listen(5000, "0.0.0.0", () => console.log("Listening on port 5000"));

We'll install express and run this application in a Docker container

docker run \
  --name loopback_unreachable \
  --rm --detach \
  --publish 3001:3000 \
  --publish 4001:4000 \
  --publish 5001:5000 \
  --workdir /var/code \
  --volume $(pwd)/index.js:/var/code/index.js \
  node:12.18.1-alpine3.12 \
  /bin/sh -c 'npm install [email protected] && node /var/code/index.js'

From the --publish flags we can see the server ports from the container have been exposed by adding one to each port value. Trying to hit these ports on the host3, we can see port 4001 — the one that is bound explicitly to 127.0.0.1 in the container — is unreachable:

$ curl http://localhost:3001
Hello World!
$ curl http://localhost:4001
curl: (52) Empty reply from server
$ curl http://localhost:5001
Hello World!

Don't forget to clean up:

docker rm --force loopback_unreachable
  1. The "any host" IP is 0.0.0.0 for IPv4 and :: for IPv6
  2. The loopback IP is 127.0.0.1 for IPv4 and ::1 for IPv6.
  3. To clarify, "on the host" is meant to distinguish from "inside the container".

Comments