EasyTier 重新打洞:把内网穿透入口从服务节点上剥离
没有任何公网设备? EasyTier 把隧道或内网穿透当成直连,使得打洞不积极,导致连接慢或延迟高? 在内网服务器上部署专做打洞节点的 EasyTier 服务即可解决!
背景
有若干内网服务器和内网终端设备想要组网。 于是它们全都部署了 EasyTier 服务。
然而至少要有一个公网可访问的 EasyTier 节点才能实现对其它内网设备的打洞, 所以直觉是给一个内网服务器配置 CloudFlare Tunnel 或 FRP 等实现公网能访问到该节点。
- frp 配置:第三方 frps 的公网端口,TCP 和 UDP 分别映射转发到服务器的
11010; - Cloudflare Tunnel 配置:把本地的 WebSocket 监听转成公网
wss://。
配置完实测证明直觉没错,所有的设备都连接起来了,但问题也随之显现。
问题
设备与服务器之间很慢、延迟高,配置 latency_first = true 仍无法改善。 easytier-cli peer 执行结果里服务节点的 cost 为 p2p、tunnel 是 tcp,wss,udp; 看似打洞并直连成功了,但实际上数据传输还是要经过 CloudFlare Tunnel 和 frp。
解决方案
从《原因》可见问题出在服务节点自身暴露了被代理地址。 那把暴露面搬到另一个 EasyTier 服务实例上不就解决了?
修改原本服务配置,收回被代理地址:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27hostname = "node-svc"
instance_name = "example-mesh"
instance_id = "<保留原 UUID>"
ipv4 = "10.10.0.1/24"
ipv6_public_addr_auto = true
dhcp = false
listeners = [
"tcp://0.0.0.0:11020", # 打洞依赖真实网卡的 NAT 映射,
"udp://0.0.0.0:11020", # 所以不应绑定回环地址。
]
[network_identity]
network_name = "example-mesh"
network_secret = "<secret>"
# 指向同机的入口实例 B。
[[peer]]
uri = "udp://127.0.0.1:11010"
[[peer]]
uri = "tcp://127.0.0.1:11010"
[flags]
accept_dns = true
tld_dns_zone = "your.tld."
enable_exit_node = true
latency_first = true
need_p2p = true # 请优先建立 P2P。新建作为入口或中继实例的配置,接管公网暴露:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21hostname = "node-gw"
instance_name = "example-mesh-gw"
instance_id = "<另一个 UUID>"
dhcp = false
# 不分配 IPv4 以进入 relay-only 模式。
# 该模式只转发数据包,不建立 TUN。
listeners = [
"tcp://0.0.0.0:11010",
"udp://0.0.0.0:11010",
"wg://0.0.0.0:11011",
"ws://0.0.0.0:11011/",
]
[network_identity]
network_name = "example-mesh"
network_secret = "<secret>"
[flags]
private_mode = true # 已暴露公网,只服务本网络。
latency_first = true
no_tun = true # 理同不分配 IPv4。保险起见设置一下。注册两个服务、启用服务并运行实例。此处不赘述方案,我反正是用的 Systemd。
1
2
3
4
5# A:注册为系统服务,以 root 身份运行。(毕竟要自动配置 TUN 什么的)
/usr/bin/easytier-core -c /etc/easytier/config.toml
# B:可注册为用户服务,无需 root 身份。
/usr/bin/easytier-core -c ~/.config/easytier/gw.toml --rpc-portal 127.0.0.1:15889dev_name留空即可自动区分 TUN 名。用内网穿透服务把实例 B 映射到公网。
验证。执行
easytier-cli peer。示例:IPv4 节点主机名 cost lat(ms) tunnel 说明 10.10.0.1/24 node-svc Local - - 本机 node-gw p2p 0.11 tcp,udp,tcp6 同机回环 10.10.0.2/24 laptop-on-wifi p2p ~2 tcp,udp 代理路径消失 10.10.0.3/24 phone-on-mobile p2p ~58 udp6 延迟和丢包明显改善 对打洞后的隧道做端到端确认:
1
2
3ping -c 20 10.10.0.3
20 packets transmitted, 18 received, 10% packet loss
rtt min/avg/max/mdev = 54.6/64.2/82.0/7.9 ms
原因
截止 2026-10-29,在 v2.6.4 版本:
若监听器收到连接即登记为直连 PeerConn:
instance/listeners.rs::run_listener()收到隧道后调用peer_manager.handle_tunnel(),把它登记进PeerMap(L237-254)。客户端显式连接被代理地址时也被认为与目标节点建立 PeerConn:
若客户端的
[[peer]]里配置的是 frp 或 CloudFlare Tunnel 的公网地址, 连接后,这条隧道在 EasyTier 视角和普通直连没有区别。已有 PeerConn 的节点会被打洞器直接跳过:
DIRECT或p2p状态不一定代表物理直连:只要
route.cost == 1,easytier-cli就把next_hop显示为DIRECT(easytier-cli.rs L1764-1777);cost == 1只表示 OSPF 路由表里一跳内可达,就是说任何直连 PeerConn 都满足,包括经映射或隧道中转的那条。 真正反映物理链路的是peer表的tunnel列(wss、tcp或udp)和cost(p2p或relay(n))。
那说白了,就是因为 EasyTier 觉得已经是直连了,没必要打洞导致的。
而 latency_first 配置没用是因为它只在已存在的可用路径里选择延迟最低的,详见 p2p-optimize。
注意事项
- 同机多实例的最小差异集:所监听的端口、
instance_name、instance_id、rpc-portal。 - 不应显式配置
stun_servers = [],必须省略不写以采用内置 STUN。若写成空数组会关闭 STUN,此时 NAT 类型退化为Unknown,基本无法打洞。 - UPnP 会自动额外发布 mapped listener。若路由器支持,就会多出一条公网 UDP 映射,需要时可配置
disable_upnp = true保证行为确定。详情见common/upnp.rs。
EasyTier 重新打洞:把内网穿透入口从服务节点上剥离
https://blog.pj568.top/2026/10-29-Separate_EasyTier_entry_and_service/