Skip to main content

Docker Compose extra_hosts: host-gateway, Syntax and Fixes (2026)

extra_hosts adds lines to a container's /etc/hosts file. Each entry maps a hostname to an IP, for example "api.example.com=10.0.0.5". The special value host-gateway resolves to the host machine's IP, so "host.docker.internal=host-gateway" lets a container on Linux reach services running on the host. It needs Docker Engine 20.10 or newer.

Use it to reach the host from a container, to mock DNS during development, or to pin a hostname to a fixed IP.

Quick reference​

services:
app:
extra_hosts:
- "host.docker.internal:host-gateway" # reach the host machine (Linux)
- "api.example.com:10.0.0.5" # override DNS to a fixed IP
- "somehost:2001:db8::10" # IPv6 mapping

Syntax​

extra_hosts accepts a list or a map. Both give the same result.

List (short syntax). Each string is HOSTNAME=IP. The = separator is preferred since Compose v2.24.1. The older HOSTNAME:IP form still works.

services:
app:
image: my-app
extra_hosts:
- "somehost=162.242.195.82"
- "otherhost=50.31.209.229"
- "myhostv6=[::1]" # IPv6, brackets optional

Map (long syntax).

services:
app:
image: my-app
extra_hosts:
somehost: "162.242.195.82"
otherhost: "50.31.209.229"

Inside the container, /etc/hosts will include:

162.242.195.82 somehost
50.31.209.229 otherhost

The same option on the command line is --add-host:

docker run --add-host host.docker.internal=host-gateway my-app

What does host-gateway resolve to?​

host-gateway is not a hostname. Docker replaces it with an IP when it creates the container. By default that IP is the gateway of the default bridge network (docker0), usually 172.17.0.1, plus its IPv6 address if the bridge has one. Your host listens on that IP, so the container reaches the host through it.

You can change the IP in the daemon config. Edit /etc/docker/daemon.json, then restart Docker:

{ "host-gateway-ips": ["192.0.2.1", "2001:db8::1111"] }

Older daemons take a single IP as "host-gateway-ip": "192.0.2.1". The command-line flag is dockerd --host-gateway-ip. Containers created before the change keep the old IP until you recreate them.

Check that it worked​

Look at the file Docker wrote:

docker compose exec app cat /etc/hosts
docker compose exec app getent hosts host.docker.internal

If the entry is missing, the container was not recreated. docker compose restart keeps the old container and its old /etc/hosts. Run docker compose up -d instead; it recreates every service whose config changed.

Common Use Cases​

1. Accessing the Host Machine (Linux)​

As discussed in our Host Networking guide, Linux containers don't support host.docker.internal by default. You can enable it using the special host-gateway value.

services:
web:
image: nginx
extra_hosts:
- "host.docker.internal:host-gateway"

This maps host.docker.internal to the IP address of the host gateway, allowing your container to talk to services running on your local machine (e.g., a local Postgres database not in Docker).

2. Mocking DNS for Development​

If your application connects to a production domain (e.g., api.example.com), but you want to redirect that traffic to a local test server or another container during development, you can use extra_hosts.

services:
backend:
image: my-backend
# ...

frontend:
image: my-frontend
extra_hosts:
- "api.example.com:172.17.0.1" # Redirect to local IP

3. Communicating Between Containers (Legacy)​

While modern Docker Compose setups should use Docker Networks and service names for discovery (e.g., connecting to http://db instead of an IP), extra_hosts can be useful for legacy applications that require specific hardcoded hostnames. See Docker Compose networks for how service name DNS, custom networks, and isolation work.

IPv6 Support​

You can also map IPv6 addresses if your Docker daemon is configured for it.

extra_hosts:
- "somehost:2001:db8::10"

Troubleshooting​

Connection refused on host.docker.internal​

The name resolves, but nothing answers. The service on the host is almost always bound to 127.0.0.1. The container connects to the bridge IP (172.17.0.1), not to the host's loopback. Bind the host service to 0.0.0.0 or to the bridge IP. For PostgreSQL that is listen_addresses in postgresql.conf plus a pg_hba.conf line for the Docker subnet. The full walkthrough is in fixing host.docker.internal on Linux.

Timeout instead of connection refused​

A firewall on the host drops traffic from the Docker bridge. With ufw, allow the bridge subnet to the port you need, for example sudo ufw allow from 172.17.0.0/16 to any port 5432. If your service runs on a user-defined Compose network, its subnet is different. Find it with docker network inspect <project>_default.

invalid IP address in add-host: "host-gateway"​

Your Docker Engine is older than 20.10 and does not know the special value. Upgrade Docker, or put the bridge IP in directly: "host.docker.internal=172.17.0.1".

It works on Docker Desktop but not on Linux​

Docker Desktop for Mac and Windows defines host.docker.internal for every container. Docker Engine on Linux does not. Add the extra_hosts line and the same Compose file works on both.

FAQ​

Frequently asked questions

What does extra_hosts do in Docker Compose?

extra_hosts adds hostname-to-IP lines to the container's /etc/hosts file. The container then resolves those hostnames to the IPs you set, before any DNS lookup. Use it to reach the host machine, to mock a domain during development, or to pin a hostname to a fixed IP.

What does host-gateway mean in extra_hosts?

host-gateway is a special value that Docker replaces with the host machine's IP when it creates the container. By default it is the gateway IP of the default bridge network, usually 172.17.0.1. The common line is 'host.docker.internal=host-gateway', which makes host.docker.internal work on Linux. It requires Docker Engine 20.10 or newer.

Should I use = or : in extra_hosts?

Both work. The Compose specification prefers HOSTNAME=IP since Compose v2.24.1, and keeps HOSTNAME:IP for backward compatibility. The = form is easier to read with IPv6 addresses, which contain colons themselves.

How do I change the IP that host-gateway resolves to?

Set 'host-gateway-ips' (a JSON array) or the older 'host-gateway-ip' (a single string) in /etc/docker/daemon.json, then restart Docker. On the command line the flag is dockerd --host-gateway-ip. Recreate your containers afterwards, because existing containers keep the old /etc/hosts.

Why does my container get connection refused on host.docker.internal?

The hostname resolves, but the service on the host only listens on 127.0.0.1. The container connects to the bridge IP, such as 172.17.0.1, so a loopback-only service never sees the request. Bind the service to 0.0.0.0 or to the bridge IP, and allow the Docker subnet in your firewall.

Why is my extra_hosts entry missing from /etc/hosts?

The container was not recreated. docker compose restart keeps the existing container with its old /etc/hosts. Run docker compose up -d, which recreates services whose configuration changed, then check with docker compose exec <service> cat /etc/hosts.


Simplify Your Networking​

Managing DNS records and host files manually can be error-prone.

Deploy on Hostim.dev

Hostim.dev provides a platform where service discovery just works. Deploy your stack and let us handle the networking complexity.