快速修复
# 一键:--add-host 把 host.docker.internal 映射到宿主机(推荐,配置文件友好)
docker run --add-host host.docker.internal:host-gateway <镜像>
容器内 host.docker.internal 即可访问宿主机服务。
你会遇到什么
宿主机上跑着服务(MySQL、Redis、本地 API…),容器里用 localhost 或 127.0.0.1 去连,报 Connection refused。宿主机上明明能访问(宿主 curl 127.0.0.1:端口 正常);换 host.docker.internal 在 Linux 上也不通(bad address)。
本文路径:快速修复(30 秒一段命令)→ 一步步排查(可跳读)→ 原理与变体(症状/原因/证据)。赶时间直接跳到「快速修复」。
为什么会这样
容器有独立的网络命名空间:容器内的 localhost/127.0.0.1 指容器自己,不是宿主机。默认 bridge 网络下,容器里没有宿主机上那个服务,所以 Connection refused(不是防火墙,是地址根本指向容器自身)。
host.docker.internal 只有 Docker Desktop(Windows/macOS)自动注入,原生 Linux 的 Docker 默认没有。
| 地址 | Linux 默认 | 说明 |
|---|---|---|
| 容器内 localhost | 指容器自己 | 连不上宿主机服务 |
| 172.17.0.1(docker0 网关) | ✅ | 默认网关 = 宿主机 |
| host.docker.internal | ❌ 默认无 | 需 --add-host 注入 |
容器是独立网络命名空间:容器内的 localhost/127.0.0.1 解析到容器自己的回环接口,宿主机上的服务根本不在这个地址空间里——Connection refused 不是防火墙拦截,是「该地址上没有任何进程在监听」。
bridge 网络的默认网关(docker0,通常 172.17.0.1)才是宿主机的入口;host.docker.internal 只是 Docker Desktop 注入的 DNS 别名,原生 Linux 的 docker 没有这个条目,直接解析失败。
确定性推论:容器访问宿主机 = 走网关 IP(172.17.0.1,Linux 通用)或 --add-host host.docker.internal:host-gateway 注入别名(配置文件友好);且宿主服务必须监听 0.0.0.0,只监听 127.0.0.1 的话外部 IP 一样连不上——寻址和监听两层都要对。
一步步来
1. 宿主 IP(最通用) — 必做
bridge 网络的默认网关就是宿主机:
ip -4 addr show docker0
容器内访问 http://172.17.0.1:<端口>。注意宿主服务要监听 0.0.0.0 而不是只监听 127.0.0.1,否则外部 IP 也连不上。
2. host.docker.internal(推荐) — 必做
docker run --add-host host.docker.internal:host-gateway <镜像>
compose 里写 extra_hosts: - "host.docker.internal:host-gateway"。macOS/Windows 的 Docker Desktop 无需配置自带。
3. --network host(最简单,仅 Linux) — 必做
docker run --network host <镜像>
共享宿主机网络命名空间,容器内 localhost 就是宿主机。代价:不再有端口隔离,容器与宿主共用端口空间。
怎么确认修好了
容器内访问宿主机服务成功(实测输出形态):
方法1:wget http://172.17.0.1:8123/ → 成功(exit 0)
方法2b:--add-host 后 host.docker.internal:8123 → 成功(exit 0)
方法3:--network host 后 localhost:8123 → 成功(exit 0)
复现基线:默认网络容器内 wget http://localhost:8123/ → Connection refused(exit 1,实测)。
其它环境的表现
| 环境 | 说明 |
|---|---|
| 原生 Linux | host.docker.internal 默认无,需 --add-host(实测 bad address) |
| Docker Desktop(Win/mac) | 自带 host.docker.internal |
| 宿主服务监听 | 需 0.0.0.0,不能只 127.0.0.1 |
| compose | extra_hosts: - "host.docker.internal:host-gateway" |
| --network host | 仅 Linux,无端口隔离 |
症状
宿主机上跑着服务(MySQL、Redis、本地 API…),容器里用 localhost 或 127.0.0.1 去连,连不上:
wget: can't connect to remote host: Connection refused
# 或 mysql: connect to 127.0.0.1 ... failed (Can't connect)
# 或 curl: (7) Failed to connect to localhost port 8123: Connection refused
特征:服务在宿主机上明明能访问(宿主 curl 127.0.0.1:端口 正常);容器网络模式是默认 bridge;换 host.docker.internal 在 Linux 上也不通(解析失败 bad address)。
原因
容器有独立的网络命名空间:容器内的 localhost/127.0.0.1 指容器自己,不是宿主机。默认 bridge 网络下,容器里没有你宿主机上那个服务,所以 Connection refused(不是防火墙,是地址根本指向容器自身)。host.docker.internal 这个主机名只有 Docker Desktop(Windows/macOS)自动注入,原生 Linux 的 Docker 默认没有,直接解析失败。
解法
三种方式(Linux 实测均可用,按场景选):
- 宿主 IP(最通用):bridge 网络的默认网关就是宿主机,容器内访问
http://172.17.0.1:<端口>(docker0 的 IP,可用ip -4 addr show docker0查)。注意宿主服务要监听0.0.0.0而不是只监听127.0.0.1,否则外部 IP 也连不上。 - host.docker.internal(推荐,配置文件友好):Linux 上用
--add-host host.docker.internal:host-gateway把该主机名映射到宿主机(compose 里写 `extra_hosts:
- "host.docker.internal:host-gateway"
)。之后容器内host.docker.internal` 与 Docker Desktop 行为一致。macOS/Windows 的 Docker Desktop 无需配置自带。
- --network host(最简单,仅 Linux):
docker run --network host共享宿主机网络命名空间,容器内 localhost 就是宿主机,直接http://localhost:<端口>。代价:不再有端口隔离,容器与宿主共用端口空间。
验证证据
- 本地实测(2026-08-29,WSL Ubuntu,docker 29.1.3,alpine:3.20;宿主机 python3 http.server :8123 监听 0.0.0.0):
- 复现:容器内
wget http://localhost:8123/→Connection refused(exit 1); - 方法1:
wget http://172.17.0.1:8123/(docker0 宿主侧 IP)→ 成功(exit 0); - 方法2a:
wget http://host.docker.internal:8123/→bad address 'host.docker.internal:8123'(Linux 默认无此主机名,exit 1); - 方法2b:
--add-host host.docker.internal:host-gateway后同一 URL → 成功(exit 0); - 方法3:
--network host后wget http://localhost:8123/→ 成功(exit 0)。 - 实测复现日志(2026-08-29)
相关 canonical
按「前置 → 同根 / 同域 / 相关」读:
- 前置(先排除):
- Docker daemon 连不上(前置:容器能起 = daemon 正常)
适用工具 (1)
本问题方案已挂到下列工具的方案页——从工具页也能回到这里,双向可达。
docker · 外部工具成套方案 (组合包)
这个问题包含在下列成套安装方案中。
- docker-compose 开发环境 verified
来源与证据
← 编码代理与终端 问题域 | 问题货架 | 遇到其它问题?去 问题空间 提交求助卡