How to connect to the Docker host from inside a Docker container?

Tim van Baarsen
5 min readSep 4, 2021

As of Docker version 18.03, you can use the host.docker.internal hostname to connect to your Docker host from inside a Docker container.

This works fine on Docker for Mac and Docker for Windows, but unfortunately, this is not was not supported on Linux until Docker 20.10.0was released in December 2020.

Starting from version 20.10 , the Docker Engine now also supports communicating with the Docker host via host.docker.internal on Linux. Unfortunately, this won't work out of the box on Linux because you need to add the extra — add-hostrun flag:

--add-host=host.docker.internal:host-gateway

This blog post demonstrates the issue on Linux using a simple example and also explains the configuration to make sure you have an identical behavior across Linux, Mac, and Windows.

From the Docker documentation for MacOS and Windows:

The host has a changing IP address (or none if you have no network access). We recommend that you connect to the special DNS name host.docker.internal which resolves to the internal IP address used by the host. This is for development purpose and will not work in a production environment outside of Docker Desktop for Windows / Mac.

You can also reach the gateway using gateway.docker.internal.

Docker version

At the time of writing this blog post, the latest stable Docker version is:

docker -v
Docker version 20.10.8, build 3967b7d

You need to have at least Docker version 20.10.0 installed to make this example work on Linux machines.

Why do I even want to reach my Docker host from inside a Docker container?

Before diving into the issue and solution, it’s good to understand a use case; why do I even need to reach the Docker host from inside my running Docker container?

Practical example:
I’m a Spring Boot developer and building a new feature into my application. For observability reasons, I add custom metrics to my code. The metrics are exposed via a Spring Boot actuator endpoint in a way Prometheus can read them. On top of the metrics, I would like to create Grafana dashboards.

For development purposes, I like to run Prometheus and Grafana in Docker while I’m developing my application in my favorite IDE, IntelliJ.

After I implemented my changes, I launch the application from my IDEA, and the application will start on my host.

In Docker, both Prometheus and Grafana are running. Before I can build some nice dashboards, Prometheus needs to scrape the metrics endpoint of my application and will continue to do so on a configured interval. Once again, the Spring Boot application is not running in Docker but on the host itself!

Prometheus is configured to reach the Spring Boot application running on the Docker host using the special DNS name: host.docker.internal

Simple example

To not bother you with a complete Grafana and Prometheus setup but still be able to show the default behavior on Linux, we will use the following setup:

  • We run a simple Spring Boot application that exposes a REST endpoint returning a ‘Hello World’ message.
  • We start a Ubuntu container in Docker and execute a REST call to the Spring Boot application running on the host OS(Linux) using curl.

You can clone the example from Github: https://github.com/j-tim/connect-docker-host-from-docker-container-example

Prerequisites

  • Make sure to have Java 11 installed
  • Spring Boot CLI installed (make sure not to install version 3 or later, since the run command has been removed since 3.x)
  • Docker installed

The Spring Boot Hello World application code (groovy) will:

  • expose a REST endpoint
  • start at port 8080

First, start the Spring Boot application using the Spring Boot CLI:

spring run helloWorld.groovy

Please note the run command has been removed from the CLI since version 3.x! Use the latest 2.7.x version of the Spring Boot CLI to make this example work.

Start an Ubuntu container:

docker run -it ubuntu bash
  • it is short for --interactive plus --tty
  • executing the command take you directly inside the container
  • allows you to interact with /bin/bash inside the container
  • Long story short: you will have abash session inside an Ubuntu Docker container

Inside the Ubuntu container, install curl:

apt update && apt install curl -y

Do a call to the Spring Boot application running on the host using curl:

curl http://host.docker.internal:8080

Because we didn’t start the container with the extra run flag, we will run into the following issue on Linux (on both Mac and Windows, it will just work fine):

root@8024db7c38fe:/# ping host.docker.internal
ping: host.docker.internal: Name or service not known

How to make it work?

On Linux, you can’t automatically resolve host.docker.internal, you need to provide the following run flag when you start the container:

--add-host=host.docker.internal:host-gateway

In the example of the Ubuntu container:

docker run -it --add-host=host.docker.internal:host-gateway ubuntu bash

When you repeat the steps again, you now can reach the Spring Boot application that is running on the host from inside the Ubuntu container:

root@c1d299ee554d:/# curl http://host.docker.internal:8080
Hello world container. You are able to reach the Docker host!

How about Docker compose?

Most of the time I use Docker compose to start my Docker containers. To get the same behavior, you need to specify the host.docker.internal:host-gateway using the extra_hosts parameter.

See docker-compose.yml example:

Other special DNS names

  • gateway.docker.internalto reach the gateway

On Mac and Windows, it is possible to use:

  • docker.for.mac.host.internal (replaces docker.for.mac.localhost)
  • docker.for.win.host.internal (replaces docker.for.win.localhost)

Conclusion

  • It’s easy to connect to the host OS from inside a Docker container
  • Avoid the use of OS-specific DNS names flavors like: docker.for.mac.host.internal
  • In Docker for Mac and Docker for Windows, you can connect to the host out of the box by using the special DNS name:host.docker.internal
  • For Linux, you need the magic string host-gateway to map to the gateway inside the container. This allows you to use the hostname host.docker.internal to access the host from inside a container.
  • To get a consistent behavior on all platforms (Mac, Windows, and Linux) use host.docker.internal:host-gateway in your Docker compose file.
  • Play around yourself! Clone my Github repo.

Resources

Tap the 👏 button if you found this article useful!

Any questions or feedback?
Reach out to me on Twitter: @TimvanBaarsen

--

--

Tim van Baarsen

I’m a creative and passionate software developer living in the Netherlands. Occasional meetup & conference speaker.