




最可靠方式是执行ip route | awk '/default/ {print $3}'获取宿主机网关IP;Linux需手动添加--add-host=host.docker.internal:host-gateway才支持该域名解析;推荐通过环境变量HOST_IP注入宿主机IP。
PHP 运行在 Docker 容器里,默认 $_SERVER['SERVER_ADDR'] 或 gethostbyname('localhost') 返回的是容器自己的网络地址(比如 172.17.0.2),不是宿主机真实 IP。要让 PHP 调用宿主机上的服务(如 MySQL、Redis、本地开发 API),必须拿到宿主机在 Docker 网络中的真实网关地址。
最可靠的方式是利用 Docker 默认桥接网络的网关规则:宿主机对容器而言,其 IP 就是默认路由的网关 IP。
ip route | awk '/default/ {print $3}',通常输出类似 172.17.0.1 —— 这就是宿主机在 docker0 网桥上的 IPexec('ip route | awk \'/default/ {print $3}\'', $output) 拿到该值,$output[0] 即目标 IPiproute2 工具,Alpine 镜像需先 apk add iproute2;Debian/Ubuntu 镜像一般自带docker network create mynet),网关可能不同,建议改用 host.docker.internal(见下一条)host.docker.internal 在 PHP 里有时不生效Docker Desktop(macOS/Windows)默认注入 host.docker.internal 到容器 hosts,但 Linux 上默认不支持,除非手动启动时加 --add-host=host.docker.internal:host-gateway。
docker run --add-host=host.docker.internal:host-gateway ...
extra_hosts: - "host.docker.internal:host-gateway"
gethostbyname('host.docker.internal') 即可,无需 exec 外部命令,更轻量也更稳定--add-host,gethostbyname() 会返回 false 或空字符
$_SERVER['REMOTE_ADDR'] 和 gethostname() 都不能用来取宿主机 IP这两个是高频误用项,务必避开:
$_SERVER['REMOTE_ADDR'] 是客户端(比如浏览器)的真实 IP,跟宿主机无关;在 Nginx + PHP-FPM 架构中还可能被反向代理覆盖,需靠 X-Forwarded-For 解析,但依然不是宿主机gethostname() 返回的是容器自身的 hostname(如 abc123def456),不是 IP,且解析出来的通常是容器 ID 对应的短名,gethostbyname() 后大概率还是回环地址/etc/hosts 或 /proc/net/route 手动解析,容易因格式差异或权限失败(尤其非 root 容器),不推荐自动探测(exec 或 DNS)在 CI/CD、快速扩缩容、多网络场景下容易出错。更可控的做法是启动时由编排层明确注入。
-e HOST_IP=192.168.1.100(填你宿主机的真实局域网 IP)$_ENV['HOST_IP'] 或 getenv('HOST_IP')
environment: - HOST_IP=192.168.1.100
127.0.0.1,宿主机的 127.0.0.1 对容器不可达;也不要依赖 DHCP 分配的 IP,建议静态配置或通过脚本生成后注入实际中最容易卡住的地方,是以为 host.docker.internal 在所有平台开箱即用,结果在 Linux 服务器上死活解析不出来——它真不是默认存在的。