2 minute read

Update! From Windows 1809 onwards this is no longer an issue!

See 6 Things You Can Do with Docker in Windows Server 2019 That You Couldn’t Do in Windows Server 2016

Docker provides network integration between containers and the host, so when the host receives network requests, they can be routed to a container. On the Docker side, the process is the same on Linux and Windows. This command runs a web server container on Linux and publishes one port:

docker run -d -p 80:80 nginx:alpine

This will start Nginx, and publish port 80 from the container to port 80 on the host. When the host receives a request on port 80 on any of its network adapters, the request gets forwarded to port 80 in the container. If you do this on Linux you can run curl http://localhost and see the response from the container:

> curl http://localhost                                         
<!DOCTYPE html>

The Linux networking stack can receive external requests on its network interfaces, and forward them to Docker containers, and it does the same with loopback requests (to localhost or and direct local requests to the container’s IP address:

Docker NAT in Linux

In the Windows world the loopback side of this doesn’t work right now, only the external request routing. The equivalent to run a standard Web server in the Windows world is:

docker run -d -p 80:80 microsoft/iis

That starts IIS running in a container and publishes port 80, mapping to port 80 inside the container. But if you browse to http://localhost on the container host, you won’t see the site because of a limitation in the default NAT network stack:

Container endpoints are only reachable from the Windows host using the container’s IP and port

Full details are here - WinNAT Capabilities and Limitations.

External requests are routed correctly, so from outside the host you can make a request to port 80 and it will be routed to the container, but if you try to access the site from localhost you’ll get an error:

> curl http://localhost
curl : Unable to connect to the remote server

To access the site on the Windows Docker host, you need to make the request using the container’s IP address - which is the virtual IP address only visible to the host machine (and the port the container exposes if it’s different to the published port, which is where the host is listening for external requests):

Docker NAT in Windows

You can get the container’s IP address with docker inspect:

docker inspect --format '' <container>

And then you can browse to the site:

Docker NAT in Windows

Hopefully this limitation will be addressed soon. You can see it in action on my YouTube video: Windows Containers and Docker: The 101