DEV Community

Stefan Natter πŸ‡¦πŸ‡ΉπŸ‘¨πŸ»β€πŸ’»
Stefan Natter πŸ‡¦πŸ‡ΉπŸ‘¨πŸ»β€πŸ’»

Posted on • Updated on

Docker Tip - How to use the host's IP Address inside a Docker container on macOS, Windows, and Linux

Once in a while, you may need your Docker host's IP address. For instance, you need to be able to connect to the host network from inside a Docker container to access your app or database running locally on the host. Debugging or reverse proxies running on your host are two additional example use-cases.

I'll show you how to easily make this work simultaneously for macOS, Windows, and Linux - because their docker networking settings differ.

Docker Networking on macOS and Windows vs. Linux

For macOS and Windows the following special DNS name can be used:

The host has a changing IP address (or none if you have no network access). From 18.03 onwards our recommendation is to 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 Mac/Windows.

The gateway is also reachable as gateway.docker.internal.

Source: https://docs.docker.com/docker-for-mac/networking/#use-cases-and-workarounds
Source: https://docs.docker.com/docker-for-windows/networking/#use-cases-and-workarounds

On Docker for Linux, the IP address of the gateway between the Docker host and the bridge network is 172.17.0.1 if you are using default networking.

Do you see the problem already? They are different, so you cannot simply run docker-compose up -d and all operating systems behave the same. But I got you covered, there's an easy approach to make this work.

Setup docker-compose

I've seen some suggestions, like creating a Linux-specific config file docker-compose.override.yml (docs), but the solution a co-worker of mine came up with seems more elegant and less complex to me.

# docker-compose.yml
version: '3.7'

services:
  app:
    image: your-app:latest
    ports:
      - "8080:8080"
    environment:
      DB_UPSTREAM: http://${DOCKER_GATEWAY_HOST:-host.docker.internal}:3000
Enter fullscreen mode Exit fullscreen mode

So, what is happening here? The DB_UPSTREAM should point to the host's IP and port 3000. ${DOCKER_GATEWAY_HOST:-host.docker.internal} is the critical piece here. This expression tells docker-compose to either us the environment variable DOCKER_GATEWAY_HOST or use the fallback host.docker.internal when resolving this value.

On both macOS and Windows it works out of the box now without anything left to do. πŸš€

If you are running this stack on Linux you need to have the DOCKER_GATEWAY_HOST environment variable set for the Docker gateway host. Simply put this line into your .bashrc (.bash_profile or .zshrc):

export DOCKER_GATEWAY_HOST=172.17.0.1
Enter fullscreen mode Exit fullscreen mode

Now you can start the stack from macOS, Windows, and Linux without further configuration or overwrites. If you stick to this pattern - as we do - this works for every project of your company.

Great, isn't it? I hope this saves you some time!

References

  • compose-file#extra_hosts: an entry with the ip address and hostname is created in /etc/hosts inside containers at build-time.

>> Let's connect on Twitter 🐦: https://twitter.com/natterstefan <<

Discussion (12)

Collapse
thiagorb profile image
Thiago RomΓ£o Barcala

Another alternative is to add the entry below to your Linux host's /etc/hosts:

172.17.0.1 host.docker.internal
Enter fullscreen mode Exit fullscreen mode

Then you can simple define the environments as:

  DB_UPSTREAM: http://host.docker.internal:3000
Enter fullscreen mode Exit fullscreen mode
Collapse
waterloomatt profile image
Matt Skelton • Edited on

Running WSL (Ubuntu 20.04 LTS), I added this to my .bashrc file.

export DOCKER_GATEWAY_HOST="`/sbin/ip route|awk '/dev eth0 proto kernel/ { print  $9}'`"
Enter fullscreen mode Exit fullscreen mode

This runs /sbin/ip route, searches for the line containing "dev eth0 proto kernel", then grabs the 9th element from that line which corresponds to the IP address.

Then, in docker-compose.yml I referenced it here,

environment:
    - ...
    - PUBLIC_HOST=$DOCKER_GATEWAY_HOST
    - ...
Enter fullscreen mode Exit fullscreen mode
Collapse
horaciodegiorgi profile image
Horacio Degiorgi • Edited on
export DOCKER_GATEWAY_HOST="`hostname -I` |awk '{print $1}'  `" 
Enter fullscreen mode Exit fullscreen mode

to automatize the iP (only get the first)

Collapse
natterstefan profile image
Stefan Natter πŸ‡¦πŸ‡ΉπŸ‘¨πŸ»β€πŸ’» Author

Thanks for the feedback!

Collapse
ibejohn818 profile image
John Hardy

if you need the host.docker.internal (for example, nginx proxy to your host network), use an entrypoint script (IE: ENTRYPOINT['/entrypoint.sh'])

" install iputils-ping & iproute2 (or like packages)
" check if the host name resolves,
" if not, then get the gateway of the current network (which is the host)
" and set it in the containers host file

!/bin/sh

HOST_DOMAIN="host.docker.internal"
ping -q -c1 $HOST_DOMAIN > /dev/null 2>&1
if [ $? -ne 0 ]; then
HOST_IP=$(ip route | awk 'NR==1 {print $3}')
echo -e "$HOST_IP\t$HOST_DOMAIN" >> /etc/hosts
fi

Cheers ;-)

Collapse
jveillet profile image
Jeremie Veillet

Nice trick!! I I was searching for a solution like this since I moved to an Ubuntu machine at work. Thanks a ton! πŸ‘

Collapse
natterstefan profile image
Stefan Natter πŸ‡¦πŸ‡ΉπŸ‘¨πŸ»β€πŸ’» Author

Hi Jeremie,

Thanks for the feedback. I’m happy I could help you. ✌️

Collapse
nialljoemaher profile image
Niall Maher

Nice! This could definitely come in handy!

Collapse
natterstefan profile image
Stefan Natter πŸ‡¦πŸ‡ΉπŸ‘¨πŸ»β€πŸ’» Author

Thanks Niall. It does - resolved some issues for our team.

Collapse
aguedeney profile image
Alan Guedeney

This is broken (at least on MacOS). I don’t get the host’s IP address. I get 192.168.65.3 for host.docker.internal. Am I missing something?

Collapse
neftedollar profile image
Roman Melnikov

As I understand 'host.docker.internal' inside docker default network will be bonded to your host machine. If you can access with 'host.docker.internal' your host ports then everything is ok

Collapse
uebmaster profile image
Uebmaster

this could be used it in linux for production?