使用EasyTier异地组网

封面
(封面图源EasyTier官网)

TL;DR

异地组网,我一直以来都有这个需求,便于在各种情况下访问我的所有内网设备。在曾经的折腾一番CloudFlare DDNS一文中我提到了使用开源的VPN协议进行异地组网,但这一直有几个弊端:

  1. 必须依赖中继服务器
  2. 只能单向访问,如需双向访问则还要另开一个ssh端口转发。
  3. 每多一个子网,就得多一条VPN连接。
    正好,在同学的安利下,碰到了这款叫EasyTier的开源项目。
    好耶,甚至是Rust开发的!

Rust Meme

架构思路

在EasyTier中,没有客户端服务器的概念,只有节点的概念,因为它是一个去中心化的网络架构。每个设备都是一个节点,EasyTier把每个节点放在同一个网段下,节点以局域网地址来访问另一节点的指定端口。
在工作的时候,需要一个公网服务器,用作STUN打洞,亦或做流量中转。

搭建目标

我要把公网服务器、手机、笔记本电脑放在同一个局域网下,其中手机通过流量上网,笔记本通过校园网WiFi上网。
其中手机和笔记本电脑要保证能正常走流量代理的情况下又不影响EasyTier组网,还要保证手机在校外能访问校内的一台服务器(10.1.2.3/16)。
因为EasyTier是以本地应用程序运行的,如果在电脑上直接裸跑,就会让系统防火墙在局域网内直接被架空,所以我们要部署到docker容器里做到网络隔离,又要保证能正常组网。

开始搭建

文件准备

我们先去release页面下载app-universal-release.apkeasytier-linux-x86_64-v2.4.5.zip两个包,一个是给安卓手机用的,一个是给我们的服务器和电脑用的。
解压后,我们只需要easytier-clieasytier-core两个就行,core用来组网,cli用来管理状态。

截止写稿,最新版本是2.4.5,请根据实际情况下载。

除安卓端,启动命令都是./easytier-core -c config.toml,后续默认你已将easytier-clieasytier-core放在工作目录,并已cd进去。后续是每个端上的配置文件。

公网服务器端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
hostname = "my_serverr"  # 节点设备名
instance_name = "mynetwork"
instance_id = "11451419-1981-0114-5141-919810114514" # UUID必须唯一
ipv4 = "172.16.32.247/24" # 该节点在网络中的CIDR格式ip地址
dhcp = false # 如为true则上面那行可以直接删去
listeners = [
   "tcp://0.0.0.0:11010", # 将本节点用作宣告服务器监听的端口。注意,后面要用这个端口,把它记住。
   "udp://0.0.0.0:11010", # 同上
   "wg://0.0.0.0:11011", # WireGuard入站,用于单向组网
]
rpc_portal = "0.0.0.0:0" # easytier-cli的通信地址,0端口表示随机

[network_identity] # 进入局域网的认证信息
network_name = "mynetwork"
network_secret = "your_password"

[flags]
no_tun = true # 这项若为false则可能与电脑上基于TUN的代理软件打架
private_mode = true # 只给我自己用做宣告服务器,不给别人用,必须要求认证信息正确才能连接,防止我这个机器加入别人的网络,或者被别人偷跑流量
relay_network_whitelist = "mynetwork" # 只允许对这些网络进行relay, 空格分割的通配符列表,如 "ab* abc",留空则不给任何网络relay

笔记本电脑端

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
hostname = "laptop"
instance_name = "laptop"
instance_id = "11451419-1981-0114-5141-919810114515"
ipv4 = "172.16.32.248/24"
dhcp = false
listeners = [ # 笔记本电脑不想当宣告服务器
# "tcp://0.0.0.0:11010",
# "udp://0.0.0.0:11010",
# "wg://0.0.0.0:11011",
]
rpc_portal = "0.0.0.0:0"
socks5_proxy = "socks5://0.0.0.0:1145" # 用于其他代理软件的代理规则,防止没法访问内网设备

[network_identity]
network_name = "mynetwork"
network_secret = "your_password"

[[peer]]
uri = "tcp://your_ip_or_domain:your_port" # 你的公网服务器监听的地址,your_port就是上面要你记住的宣告服务器的那个端口

[[proxy_network]]
cidr = "10.1.2.3/16" # 校内服务器。这样配置后会把校园网的10.1.0.0/16整个网段也映射到你的虚拟局域网里。

[flags]
no_tun = true # 防止和其他TUN类的代理软件打架
private_mode = true

安卓端

打开app,在basic settings里填入你这台设备的虚拟局域网ip地址,或者也可选择是否DHCP获取。
Network NameNetwork Secrect填入和上面配置文件里一样的。
Networking Method选择Public Server,然后地址填写tcp://your_ip_or_domain:your_port,也和上面配置文件一样。
重点来了,你如果要在组网的同时使用别的代理软件,就要打开No TUN Mode并添加Socks5 Server,然后去第三方代理软件里添加一条路由规则,这个会在文章最后讲到。

然后直接Run Network即可。

笔记本端的安全策略: 使用Docker隔离网络访问

因为EasyTier是以本地应用程序运行的,如果在电脑上直接裸跑,就会让系统防火墙在局域网内直接被架空,所以我们要部署到docker容器里做到网络隔离,又要保证能正常组网。

现假设你的电脑上运行着ssh服务(监听1919端口)和nginx页面(监听9180端口),并且这两个端口已被防火墙放通。

Docker容器

创建一个Docker容器,把1145端口(就是上面笔记本配置文件里的socks5_proxy端口)映射出来。或者可以直接抄我的作业:

1
sudo docker run -d --name alpine_easytier -p 1145:1145 -v /home/admin/easytier:/root -v /etc/localtime:/etc/localtime -dit alpine

这样在容器里运行easytier的话,别的节点通过局域网ip访问你的时候是无法直接访问宿主机对应端口的服务的(实际访问的是容器里对应的端口),所以我们要用端口转发器把流量从容器里转发到宿主机上。即使宿主机对应端口被防火墙拦了,别的节点也无法访问该服务,对别的节点来说是无感的了。
我们使用socat进行端口转发,这样更通用,因为在我的环境下,alpine容器里装iptables无法修改转发规则。

使用socat转发流量只须这一行命令即可(容器中宿主机ip是172.17.0.1):

1
2
socat TCP-LISTEN:1919,bind=0.0.0.0,fork,reuseaddr TCP:172.17.0.1:1919
socat TCP-LISTEN:9810,bind=0.0.0.0,fork,reuseaddr TCP:172.17.0.1:9810

或者使用这个脚本启动,可以自动管理socateasytire-core的生命周期:

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
28
29
30
31
32
TARGET_HOST="172.17.0.1"
PORTS_TCP="1919 9810"
PORTS_UDP=""

cleanup() {
echo "正在清理..."
killall socat
echo "所有 socat 进程已停止"
exit
}

trap cleanup INT TERM
killall socat
echo "启动端口映射到 $TARGET_HOST..."

for PORT in $PORTS_TCP; do
echo "映射端口: 0.0.0.0:$PORT/tcp -> $TARGET_HOST:$PORT/tcp"
socat TCP-LISTEN:$PORT,bind=0.0.0.0,fork,reuseaddr TCP:$TARGET_HOST:$PORT &
done

for PORT in $PORTS_UDP; do
echo "映射端口: 0.0.0.0:$PORT/udp -> $TARGET_HOST:$PORT/udp"
socat UDP-LISTEN:$PORT,bind=0.0.0.0,fork,reuseaddr UDP:$TARGET_HOST:$PORT &
done

echo "所有端口映射已启动"
echo "按 Ctrl+C 停止并退出"

./easytier-core -c config.toml

# 等待所有后台进程
wait

和其他TUN代理的冲突问题

如果你开了easytier的tun模式,会和其他基于tun实现的代理软件对冲(在安卓上系统会限制只允许有一个VPN Service导致互挤);如果你部署到docker容器里的话,会导致无法连上宣告服务器。所以我们要进行如下处理:

假设你的容器已将socks5端口1145转发出来。

在代理软件里新增一个节点,地址是127.0.0.1:1145,设置代理软件的路由规则,发往10.1.0.0/16172.16.32.0/24的流量通过该节点出站。
(安卓不用做这一步)然后设置排除网卡,把docker0排除掉即可。


使用EasyTier异地组网
http://blog.coolenoch.ink/2025/10/07/Linux/25-使用EasyTier异地组网-251007/
作者
CoolestEnoch
发布于
2025年10月7日
许可协议