本篇由 Gemini 3.1 Pro 生成
记录一次解决 Docker 容器走宿主机透明代理时遇到超时的排障过程。问题比较典型,主要卡在 Linux 内核的防火墙框架冲突上。
场景与问题
需求是让 Docker 里的 Twikoo 容器走代理,以便连通 Telegram API 和 Akismet 反垃圾接口。
一开始试了常规方案:
- 配置环境变量:加了
HTTP_PROXY,但 Node.js 底层默认不认系统代理变量,无效。 - 端口桥接:用
socat劫持并转到主机的 7890 端口,操作繁琐且容易触发主机的端口占用(Address in use)或 Docker 的网关隔离(Connection refused)。
最后决定直接用宿主机上的 ShellCrash 做底层透明代理,划定一个 Docker 网段让其全局接管。但在配置好之后,遇到了一个非常诡异的现象:
容器的 DNS 解析成功了(拿到了返回的 Fake-IP 或真实 IP),但紧接着的 TCP 连接全部报 ETIMEDOUT 超时。
根本原因
排查宿主机内核路由表后发现,这是 nftables 和 iptables 两套防火墙框架在“打架”。
- 目前新版的代理软件默认使用较新的
nftables框架来接管和重定向流量。 - 但是 Docker 容器的网络打通(NAT 和网桥)依然重度依赖
iptables。
当 Twikoo 发出的流量被代理软件的 nftables 规则强行重定向到代理端口时,这个被修改过流向的数据包到了 Docker 的 iptables 链里,被视为了非法篡改的异常包,直接被底层 DROP(丢弃)了。
这就导致了“DNS 通了,但数据包发不出去”的假死状态。
解决方案
让代理软件和 Docker 使用同一种防火墙语言即可。
1. 切换代理防火墙框架
进入代理软件(如 ShellCrash 或其他透明代理面板)的设置菜单,将流量接管/防火墙模式从 nftables 改回 iptables。重启代理服务。
2. 创建代理专用 Docker 网段
在宿主机新建一个专门用来走代理的虚拟网络(例如 172.30.x.x):
docker network create --subnet=172.30.0.0/16 proxy_net3. 配置透明代理接管
在代理软件的接管设置中,添加 172.30.0.0/16 网段。
4. 修改容器配置
现在 docker-compose.yml 可以做到极其精简,不需要写任何代理环境变量或 DNS 配置,直接让容器接入 proxy_net 即可实现无感连接:
version: '3'services: twikoo: image: imaegoo/twikoo container_name: twikoo restart: always ports: - 8080:8080 volumes: - ./data:/app/data environment: - TWIKOO_THROTTLE=1000
# --- 以下新增 --- networks: - proxy_netnetworks: proxy_net: external: true总结
以后如果有其他容器需要走代理,直接在 compose 文件里挂载这个 proxy_net 外部网络即可。底层的 DNS 防污染和国内外分流全部由宿主机的透明代理自动处理。
部分信息可能已经过时