go程序启动报“address family not supported by protocol”是因系统禁用ipv6(/proc/sys/net/ipv6/conf/all/disable_ipv6=1)而net/http默认尝试绑定[::]:端口触发af_inet6 socket失败;修复方式是将监听地址显式改为"0.0.0.0:端口",绕过ipv6探测逻辑。

Go 程序启动时出现 Address family not supported by protocol,基本可以锁定是监听地址触发了 IPv6 socket 创建,但系统禁用了 IPv6(/proc/sys/net/ipv6/conf/all/disable_ipv6 值为 1)。
为什么 http.ListenAndServe(":8080", handler) 会失败
Go 的 net/http 包在传入空地址(如 "")或仅端口(如 :8080)时,内部会尝试先绑定 [::]:8080(IPv6 wildcards),再 fallback 到 0.0.0.0:8080。一旦内核禁用 IPv6,socket(AF_INET6, ...) 系统调用直接返回 EAFNOSUPPORT,Go 就抛出这个错误。
- 即使代码里没写
[::],gin.Default().Run(":8080")、echo.Start(":8080")、fiber.Listen(":8080")等默认行为都走同一路径 - 错误不是发生在请求阶段,而是在服务启动的
net.Listen阶段,所以日志里通常只有 panic 或 fatal,没有 trace - 检查方式:
cat /proc/sys/net/ipv6/conf/all/disable_ipv6返回1即确认 IPv6 被禁用
如何快速修复 Go 监听逻辑
不改系统、不重启、不重装,只需显式指定 IPv4 地址字面量,绕过 IPv6 探测逻辑。
- 把
http.ListenAndServe(":8080", handler)改成http.ListenAndServe("0.0.0.0:8080", handler) - 若用底层
net.Listen("tcp", ":8080"),改为net.Listen("tcp", "0.0.0.0:8080") - 框架如 Gin:用
router.Run("0.0.0.0:8080")替代router.Run(":8080") - 避免任何含
[::]、::1、[::1]的字符串作为监听地址 —— 即使是注释里写了也建议删掉,防止误复制
第三方库或依赖悄悄引入 IPv6 绑定
有些工具链或中间件(比如某些 prometheus metrics exporter、grpc-go 的默认 listener、甚至 test helper)可能内部硬编码了 [::]:xxx。这类问题往往出现在集成后才暴露。
- 运行前加一句
fmt.Printf("listen addr: %q\n", addr),确认最终传给net.Listen的值 - 用
strace -e trace=socket,bind ./your-binary观察实际系统调用参数,看到AF_INET6就说明还在走 IPv6 路径 - 升级依赖时留意 changelog:例如旧版
golang.org/x/net/websocket或某些自定义 http server wrapper 有类似行为
真正容易被忽略的是:这个错误不会在所有环境复现,只在 IPv6 被禁用的服务器(如部分国产 OS、Docker 默认容器、CI runner)上爆发;本地开发跑得好好的,一上生产就挂,排查时容易绕远路去查防火墙或端口占用。











