4.9 KiB
Xray 透明代理与 DHT 直连处理
本文只适用于宿主机启用了 Xray TProxy 或其他全局透明代理的特殊部署环境
普通 Docker 主机直接使用根目录 compose.yaml 不需要这里的专用网络或 nftables 规则
为什么会发生
DHT 会向大量公网节点发送 UDP 查询 并尝试连接大量 Peer 的随机 TCP 端口
全局 TProxy 如果在 prerouting 中接管所有公网 TCP 和 UDP Docker 容器流量也会进入 Xray
Xray 即使最终选择直连出站仍然需要维护这些 UDP 会话 因此可能积累大量 socket 并让 Metadata TCP 连接失败
典型现象
- DHT 节点 Peer 和采样 infohash 持续增长
- Metadata 成功长期为零或远低于正常水平
- Metadata 失败几乎全部是连接失败
- Xray 文件描述符和宿主机 UDP socket 持续增长
- SSH 或其他新连接开始偶发断开
dht-search容器自身文件描述符并不高
仅看到 Metadata 超时不能直接判断为 Xray 问题 公网 DHT 本身就包含大量不可达 Peer
如何确认
查看服务统计
docker run --rm --network web-network curlimages/curl:8.16.0 -fsS http://dht-search:8080/stats
重点比较以下字段
metadata_ok
metadata_failed
metadata_failure_connect
metadata_failure_timeout
metadata_in_flight
查看宿主机和 Xray socket
cat /proc/net/sockstat
xray_pid="$(pidof xray)"
find "/proc/${xray_pid}/fd" -maxdepth 1 -type l | wc -l
grep "Max open files" "/proc/${xray_pid}/limits"
查看 DHT 容器自身 socket
docker exec dht-search cat /proc/net/sockstat
docker exec dht-search sh -c 'ls /proc/1/fd | wc -l'
查看透明代理规则
nft list ruleset
ip rule show
如果存在类似规则 Docker 公网流量会进入 Xray
meta l4proto { tcp, udp } tproxy to :12345 meta mark set 1 accept
推荐解决方案
让 DHT 同时连接反向代理网络和独立直连网络
networks:
web-network:
external: true
name: web-network
dht-direct:
name: dht-direct
driver: bridge
ipam:
config:
- subnet: 172.30.0.0/24
services:
dht-search:
networks:
web-network:
dht-direct:
gw_priority: 1
web-network 只负责 Caddy 到 dht-search:8080
dht-direct 具有更高网关优先级并负责 DHT 和 Peer 公网流量
部署前必须确认 172.30.0.0/24 没有与宿主机路由或其他 Docker 网络冲突
ip route show 172.30.0.0/24
docker network inspect dht-direct
配置 Xray 来源旁路
在 Xray 持久化 nftables 文件中增加来源集合
set bypass_source_ipv4 {
type ipv4_addr
flags interval
elements = {
172.30.0.0/24
}
}
在 prerouting 链进入 TProxy 之前增加
ip saddr @bypass_source_ipv4 return
必须修改 Xray 服务启动时实际加载的持久化文件 只向当前运行规则临时执行 nft add rule 会在重启后失效
安全实施顺序
- 使用
docker compose stop优雅停止 DHT - 备份 Compose 和 Xray nftables 文件
- 增加
dht-direct网络和来源旁路 - 使用
docker compose config --quiet校验 Compose - 使用
nft -c -f <规则文件>校验 nftables - 重启 Xray 释放已经积累的旧会话
- 使用
docker compose up -d重新创建 DHT 容器 - 验证默认网关 Metadata 成功率和 socket 数量
重启 Xray 会短暂中断现有代理连接 应选择允许短暂中断的时间执行
验收
确认容器同时加入两个网络且没有宿主机端口绑定
docker compose ps
docker inspect dht-search --format '{{json .HostConfig.PortBindings}}'
docker inspect dht-search --format '{{json .NetworkSettings.Networks}}'
docker exec dht-search cat /proc/net/route
默认网关应该属于 dht-direct 然后持续观察
metadata_ok和persistence_inserted开始增长- Metadata 失败不再全部是连接失败
- Xray 文件描述符不再随 DHT 流量快速增长
- 宿主机 UDP socket 恢复到正常范围
- Caddy 仍能通过
web-network访问服务
实际案例
一次远端 Debian 部署中修复前 Metadata 尝试超过一百万次但成功为零 Xray 文件描述符增长到约三十九万 主机 UDP socket 超过三十三万
增加独立直连网络并重启 Xray 后两分钟内 Metadata 成功 1222 条并入库 1218 条 Xray 文件描述符稳定在 12 主机 UDP socket 稳定在 6
不建议的处理
- 只提高 Xray
LimitNOFILE - 只增加机器内存
- 只降低 Metadata 并发
- 让 DHT 流量进入 Xray 后再选择 direct outbound
这些方法只能延迟资源耗尽或仍然让 Xray 维护海量 UDP 会话 不能消除错误流量边界
回滚
如果专用网络启动失败
- 停止 DHT 容器
- 恢复原 Compose 和 nftables 备份
- 校验并重启 Xray
- 保持 DHT 停止直到重新确认路由方案
不要在恢复了全局 TProxy 且没有来源旁路的情况下重新启动高并发 DHT