314

On Mac and Windows it is possible to use host.docker.internal (Docker 18.03+) inside container.

Is there one for Linux that will work out of the box without passing env variables or extracting it using various CLI commands?

slhck
  • 36,575
  • 28
  • 148
  • 201
klor
  • 3,596
  • 2
  • 13
  • 13
  • 4
    In 18.03 there is a docker.host.internal, but it didn't work for me. – James O'Brien Apr 05 '18 at 03:40
  • 7
    There is open [PR](https://github.com/docker/libnetwork/pull/2348) which add "host.docker.internal" feature to Linux. Wait until it will be accepted, and now as a workaround, you can use [special container](https://github.com/qoomon/docker-host) which add unified "dockerhost" host and you can use this from docker. – Serhii Popov Jul 05 '19 at 16:20
  • 1
    It should be noted that docker-for-windows is a specific product line and will not cover docker on windows in general. For example I use docker on windows, using docker-toolbox (OG) so that it has less conflicts with the rest of my setup and I don't need HyperV. There is an answer in this thread using grep, awk and netstat, which works for me; although generally, mixed network environments can also be solved with LAN or WAN level hostnames, than machine hostnames. This is then more explicit and flexible / composable than hacking at docker VM's – MrMesees Oct 06 '21 at 01:55

11 Answers11

281

Depends what you're trying to do. If you're running with --net=host, localhost should work fine. If you're using default networking, use the static IP 172.17.0.1. I suspect neither will behave quite the same as those domains.

devnev
  • 3,141
  • 1
  • 15
  • 10
  • 72
    Wow! `172.17.0.1` actually works! I found this nowhere in the documentation or any of the forums complaining about `host.docker.internal` not working. Is this IP guaranteed to always link to the host machine? – Jules Colle May 30 '20 at 14:00
  • 6
    You can edit your /etc/hosts and add 172.17.0.1 docker.host.internal – PHZ.fi-Pharazon Jul 02 '20 at 06:16
  • 7
    I can attest the `172.17.0.1`-trick this works with GitHub Actions! – Alex Sep 03 '20 at 11:00
  • 1
    I disagree that it "depends what you're trying to do". It does not depend what we are trying to do. We are trying to do only one thing that is connect to the host machine from inside the container. I already know it is discouraged and that's why we can't. But I have a task to solve. PHP-code needs to connect from inside Docker to my code editor. – Gherman Dec 09 '20 at 13:07
  • 9
    @JulesColle It is "guaranteed" as long as you are on the default network. `172.17.0.1` is no magic trick, but simply the gateway of the network `bridge`, which happens to be the host. All containers will be connected to `bridge` unless specified otherwise. [See here](https://docs.docker.com/engine/tutorials/networkingcontainers/) – FirefoxMetzger Mar 02 '21 at 14:52
  • 10
    This DOES NOT work on all cases. If you have other networks, a new interface is going to be created: 172.17.0.1, 172.18.0.1, 172.19.0.1 and so on (try `ifconfig` to list all interfaces). You have to manually obtain the IP for your network. – Federico Jun 29 '21 at 17:48
  • Is this possible while building? – Eugen Konkov Aug 06 '22 at 12:28
214

For linux systems, you can – starting from major version 20.04 of the docker engine – now also communicate with the host via host.docker.internal. This won't work automatically, but you need to provide the following run flag:

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

See the answer here: https://stackoverflow.com/a/61424570/3757139

See also this answer below to add to a docker-compose file - https://stackoverflow.com/a/67158212/243392

Brian Burns
  • 20,575
  • 8
  • 83
  • 77
Samuel
  • 4,783
  • 3
  • 29
  • 32
  • 4
    Is there a way to enable this in daemon.json or something? I'm thinking about test environments of Rancher and Kubernetes, where I don't want to take care of every single one of the many containers. – qräbnö Nov 26 '20 at 18:20
  • 6
    When running`--add-host=host.docker.internal:host-gateway` on CentOS I received the error `invalid argument "host.docker.internal:host-gateway" for "--add-host" flag: invalid IP address in add-host: "host-gateway"` Are you expecting to need to replace `host-gateway` with the actual host IP? – mummybot Dec 03 '20 at 16:08
  • 3
    The magical IP number worked: `--add-host=host.docker.internal:172.17.0.1 \` – mummybot Dec 03 '20 at 16:36
  • 2
    this works for me too. 172.17.0.1 is bridge network's gateway address in my case. if anyone has different network settings , they can get this by doing docker inspect. – Aniket Chopade Dec 08 '20 at 13:52
  • 10
    Only newer docker versions have the magical string `host-gateway`, that converts to the docker default bridge network ip (or host's virtual IP when using docker desktop). You can test running: `docker run --rm --add-host=host.docker.internal:host-gateway ubuntu:18.04 cat /etc/hosts`, then see if it works and show the ip in the hosts file (there should be a line like `172.17.0.1 host.docker.internal` in it). – Lucas Basquerotto Apr 20 '21 at 19:47
  • 1
    This is the correct answer for me! – Ed Abucay Jul 22 '22 at 10:08
  • Make sure that `live-restore: false` otherwise `host.docker.internal` doesn't seem to work under Linux. – Melroy van den Berg Jan 14 '23 at 23:14
  • Why doesn't Docker just do this automatically? I mean, really... – Quolonel Questions Aug 31 '23 at 22:04
184

If you are using Docker Compose + Linux, you have to add it manually (at least for now). Use extra_hosts on your docker-compose.yaml file:

version: '3.7'

services:

  fpm:
    build:
      context: .
    extra_hosts:
      - "host.docker.internal:host-gateway"

Do not forget to update Docker since this only works with Docker v20.10+.

Source : https://github.com/docker/for-linux/issues/264#issuecomment-784985736

jawira
  • 3,668
  • 2
  • 17
  • 27
32

One solution is to use a special container which redirects traffic to the host. You can find such a container here: https://github.com/qoomon/docker-host. The idea is to grab the default route from within the container and install that as a NAT gateway for incoming connections.

An imaginary example usage:

docker-host:
  image: qoomon/docker-host
  cap_add: [ 'NET_ADMIN', 'NET_RAW' ]
  restart: on-failure
  environment:
    - PORTS=999

some-service:
  image: ...
  environment:
    SERVER_URL: "http://docker-host:999"
  command: ...
  depends_on:
    - docker-host
Pang
  • 9,564
  • 146
  • 81
  • 122
Jonas Chapuis
  • 697
  • 5
  • 9
21

This is my solution:

IP_ADDRESS=$(ip addr show | grep "\binet\b.*\bdocker0\b" | awk '{print $2}' | cut -d '/' -f 1)

then in docker-compose:

extra_hosts:
  docker.host: ${IP_ADDRESS}
Pang
  • 9,564
  • 146
  • 81
  • 122
Antonio Petricca
  • 8,891
  • 5
  • 36
  • 74
  • 2
    On my Ubuntu VM, this is 172.17.0.1, which matches the above answer. – Dan Burton Jul 10 '20 at 15:27
  • 3
    On Linux/Debian docker with this cmd I get nothing. Better is: `/sbin/ip route|awk '/default/ { print $3 }'` – GetoX Sep 28 '20 at 08:57
  • The above `ip route` example prints the gateway, not the `docker0` io. The below should work: `# ip route | awk '/docker0/ {print $9}'` – Adam Shand Jan 03 '22 at 09:12
17

For linux there isn't a default DNS name for the host machine. This can be verified by running the command:

docker run -it alpine cat /etc/hosts

This feature has been requested, however wasn't implemented. You can check this issue. As discussed you can use the following command to find the IP of the host from the container.

netstat -nr | grep '^0\.0\.0\.0' | awk '{print $2}'

Alternatively, you can provide the host ip to the run command via docker run --add-host dockerHost:<ip-address> ...

yamenk
  • 46,736
  • 10
  • 93
  • 87
  • 1
    That's not equivalent by any means. Having something that will resolve with dns gives you the ability to put it in config files without evaluating or sed'ing, or other funky stuff. – James O'Brien Apr 05 '18 at 03:38
  • More often than not `grep | awk` can be just awk: `awk '/^0\.0\.0\.0/{print $2}'` :) – cviejo Jun 05 '19 at 10:38
  • Well I would like to say thank you. This worked on my windows setup which uses docker-machine (I know OG). Normally I run a pass-through nginx so that I can talk to docker via a single container, but talking back to the host seems to be very OS / setup specific. It worked for me and I'm ecstatic for that. Thank you! – MrMesees Oct 06 '21 at 01:24
14

https://github.com/docker/for-linux/issues/264

IP=$(ip -4 route list match 0/0 | awk '{print $3}')
echo "Host ip is $IP"
echo "$IP   host.docker.internal" | sudo tee -a /etc/hosts

It will add host.docker.internal to your hosts. Then you can use it in xdebug config.

Here is example of env variable in docker-compose.yml

XDEBUG_CONFIG: remote_host=host.docker.internal remote_autostart=On remote_enable=On idekey=XDEBUG remote_log=/tmp/xdebug.log remote_port=9999
Pang
  • 9,564
  • 146
  • 81
  • 122
Serhii Shliakhov
  • 2,631
  • 3
  • 19
  • 37
14

tldr; Access the host via the static IP 172.17.0.1

Doing HTTP request towards the host:

  1. Run the following command to get the static IP: ip addr show | grep "\binet\b.*\bdocker0\b" | awk '{print $2}' | cut -d '/' -f 1

  2. Add the new IP to allowed hosts

  3. Use the IP address just found in your requests: req = requests.get('http://172.17.0.1:8000/api/YOUR_ENDPOINT')

oligofren
  • 20,744
  • 16
  • 93
  • 180
dpacman
  • 3,683
  • 2
  • 20
  • 35
11

host.docker.internal exists only in Windows WSL because Docker Desktop for Windows runs Docker daemon inside the special WSL VM Docker-Desktop. It has its own localhost and its own WSL2 interface to communicate with Windows. This VM has no static IP. The IP is generated every time when VM is created and passed via host.docker.internal in the generated /etc/hosts to every distro. Although there is no bridge or real v-switch all ports opened on eth0 of VM internal network are mapped on the host Local network, BUT NOT ON THE ETH0 OF THE HOST. There is no real bridge and port mapping - nothing to configure. Inside WSL VM its Localhost is the same as the localhost of the Linux machine. 2 processes inside WSL VM can communicate via localhost. Cross-distro IPC must use host.docker.internal. It is possible to create bridge inside WSL VM -Docker does it.

Pavel Sosin
  • 111
  • 1
  • 3
  • 1
    actually, host.docker.internal works on OSX if using docker desktop as well – Felipe Valdes Apr 14 '22 at 16:06
  • Another hint [from the docs](https://docs.docker.com/desktop/networking/): This (using `host.docker.internal`) is for development purpose and does not work in a production environment outside of Docker Desktop. – Daniel W. Aug 10 '22 at 17:56
9

Using the docker0 interface ip, say 172.17.0.1, could be a good workaround.

Just be sure that the service you need to reach listens to external connections. A typical example is Mysql who binds to 127.0.0.1 by default, resulting unreachable until you allow external connections (es. binding to 0.0.0.0)

Michigan
  • 129
  • 1
  • 3
1

For linux, I was able to use the service name I was trying to connect to, e.g. one of my containers (php-fpm) was trying to connect to mysql, so I used mysql as the host name, since that's the service name in my docker-compose

DWils
  • 390
  • 1
  • 4
  • 16
  • 1
    This question is about connecting to the host system, not another service inside the same docker-compose environment. – burny May 07 '21 at 12:30
  • Two things: a) it is the correct answer to the underlying problem (as opposed to hacking around DNS resolution using /etc/hosts) and b) using internals of docker to do the simple thing such accessing exposed ports is, and has always been, discouraged. That's what the -p or "expose" in docker-compose does. I understand the question is a bit different, but it stems from another mistake which by mocking around with /etc/hosts is just covered - not fixed. – Matthias Hryniszak Dec 08 '21 at 09:48