EasyTier 重新打洞:把内网穿透入口从服务节点上剥离

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 服务实例上不就解决了?

EasyTier 入口与服务分离拓扑

  1. 修改原本服务配置,收回被代理地址:

    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
    27
    hostname = "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。
  2. 新建作为入口或中继实例的配置,接管公网暴露:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    hostname = "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。保险起见设置一下。
  3. 注册两个服务、启用服务并运行实例。此处不赘述方案,我反正是用的 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:15889

    dev_name 留空即可自动区分 TUN 名。

  4. 用内网穿透服务把实例 B 映射到公网。

  5. 验证。执行 easytier-cli peer。示例:

    IPv4节点主机名costlat(ms)tunnel说明
    10.10.0.1/24node-svcLocal--本机
    node-gwp2p0.11tcp,udp,tcp6同机回环
    10.10.0.2/24laptop-on-wifip2p~2tcp,udp代理路径消失
    10.10.0.3/24phone-on-mobilep2p~58udp6延迟和丢包明显改善

    对打洞后的隧道做端到端确认:

    1
    2
    3
    $ ping -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 版本:

  1. 若监听器收到连接即登记为直连 PeerConn:

    instance/listeners.rs::run_listener() 收到隧道后调用 peer_manager.handle_tunnel(),把它登记进 PeerMap (L237-254)。

  2. 客户端显式连接被代理地址时也被认为与目标节点建立 PeerConn:

    若客户端的 [[peer]] 里配置的是 frp 或 CloudFlare Tunnel 的公网地址, 连接后,这条隧道在 EasyTier 视角和普通直连没有区别。

  3. 已有 PeerConn 的节点会被打洞器直接跳过:

    • UDP 打洞:connector/udp_hole_punch/mod.rs 中 if data.peer_mgr.get_peer_map().has_peer(peer_id) { continue; } (L477-479)
    • TCP 打洞:connector/tcp_hole_punch.rs 同样是 has_peer(peer_id) 跳过 (L475)。
  4. 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。

注意事项

  1. 同机多实例的最小差异集:所监听的端口、instance_name、instance_id、rpc-portal。
  2. 不应显式配置 stun_servers = [],必须省略不写以采用内置 STUN。若写成空数组会关闭 STUN,此时 NAT 类型退化为 Unknown,基本无法打洞。
  3. UPnP 会自动额外发布 mapped listener。若路由器支持,就会多出一条公网 UDP 映射,需要时可配置 disable_upnp = true 保证行为确定。详情见 common/upnp.rs。

EasyTier 重新打洞:把内网穿透入口从服务节点上剥离

https://blog.pj568.top/2026/10-29-Separate_EasyTier_entry_and_service/

作者

PJ568

发布于

2026-10-29

更新于

2026-10-30

许可协议

评论