Table of Contents
zerotier 可谓是慕名许久,但之前一直没有太多内网穿透和异地组网的需求,此次准备在外网访问家里NAS部署的部分应用,所以也调研了一些相关的应用,最终选择了 zerotier 来对我现有的机器进行组网
FRP: 需要将服务器的端口映射出去,不太喜欢这种暴力的方式。我目前的服务基本上只会在
0.0.0.0
监听80、443等常用端口,其它服务一律监听127.0.0.1
,通过nginx访问内部的服务DDNS: 家里的NAS直接暴露在公网,这非常不安全,而且家用宽带无法使用80,443端口,只能使用高位端口
ZEROTIER: 使用 P2P 的方式对多台服务器进行组网,映射的端口只允许加入组网的设备访问,这在速度和安全性上确实是我所需要的
相关概念
-
Planet: 行星服务器,也称根服务器。主要用于管理 zerotier 客户端的地址信息
-
Moon: 月亮服务器,也称中继服务器、跳转服务器。主要用于当两台设备无法直连时,可以通过Moon中转连接
-
Leaf: 组网使用的设备,可以是一台服务器,一台NAS,甚至一台手机
部署教程
现在我有三台设备需要进行组网,一台A在国外, 一台B在国内(腾讯云),还有一台C在家里(NAS)。我准备将私有Planet部署到机器A,同时机器A也会加入到内网里,A、B、C三台设备可以通过内网相互访问
UI界面
以 jonnyan404/zerotier-planet
为例
-
创建目录
mkdir /opt/zerotier /opt/ztncui
-
部署服务
docker run -d --name ztncui --restart always \ -p 4000:4000 -p 9993:9993/tcp -p 9993:9993/udp \ -e MYADDR={服务器公网IP} \ -e HTTP_PORT=4000 \ -e HTTP_ALL_INTERFACES=yes \ -e ZTNCUI_PASSWD=mrdoc.fun \ -v /opt/zerotier:/var/lib/zerotier-one \ -v /opt/ztncui:/opt/key-networks/ztncui/etc \ keynetworks/ztncui
然后就可以通过
服务器公网IP:4000
访问UI管理界面,默认的用户名和密码:admin,mrdoc.fun
Zerotier客户端
-
Linux: 部署方式很简单,注意区分 host网络 和 bridge网络,这两个在安全性有所区别(具体在下面讲)
docker run --name zerotier -d \ --restart always \ --net host \ --cap-add NET_ADMIN \ --device /dev/net/tun \ -v /opt/zerotier:/var/lib/zerotier-one \ zerotier/zerotier:latest
如果使用私有Planet,记得替换
/opt/zerotier/planet
文件 -
Android: 推荐使用 https://github.com/kaaass/ZerotierFix
私有Planet
默认的Planet信息是硬编码在zertier代码里,如果安装好客户端后会在 zerotier-cli peers
看到官方的Planet服务器。
而部署私有的Planet的目的:
-
官方的服务器基本都位于国外或者香港,服务连通性无法得到保证
-
安全性。试想一个陌生的设备加入到网络,而这个设备的许可只需要得到官方的认证即可。当然,官方是基本不可能发生这样的情况,但如果有一个完全控制的网络,何乐而不为呢
如何生成私有Planet文件?
git clone https://github.com/jonnyan404/zerotier-planet --depth=1 cd zerotier-planet docker cp mkmoonworld-x86_64 ztncui:/tmp docker cp patch.sh ztncui:/tmp docker exec -it ztncui bash /tmp/patch.sh docker restart ztncui
这样就会在挂载目录 /opt/zerotier
下生成一个新的 planet 文件,记得下载并备份。所有加入组网的客户端都需要替换该文件
私有Planet服务器加入组网
如果按照上述部署流程也可以正常使用 zerotier
组网,但是,如果想要把部署了私有Planet的设备也加入到内网,貌似没有一篇文章说到。 所以我专门研究了一下,想要把私有Planet的机器也加入到内网,大概是可以分为下面几种方式:
-
(不推荐) 修改ztncui内部zerotier的默认端口9993
在/opt/zerotier
目录下添加一个local.conf
,并设置{ "settings": { "primaryPort": 9995 } }
然后修改
patch.sh
文件里的9993
端口,以及/start_ztncui.sh
添加一行echo "ZT_ADDR=localhost:$ZT_PORT" > /opt/key-networks/ztncui/.env
-
部署两个zerotier: 除了ztncui容器内部的一个zerotier,再在机器上部署一个客户端,并修改端口,避免端口冲突
-
(推荐) ztncui镜像的UI和zerotier分开部署
我研究后才发现ztncui
的相关镜像把事情弄的很复杂,都把ztncui
和zerotier
放到同一个镜像,专门去连接localhost:9993
。其实是可以把两个镜像分开的,UI 只做 UI ,使用 API 去连接 zerotier 官方的镜像
UI和Zerotier分开部署
如果想要自己构建Docker镜像,可以参考 honmaple/ztncui-aio
-
部署 zerotier 的客户端(部署过的可以忽略)
docker run -d --name zerotier --restart always --net=host --cap-add NET_ADMIN --device /dev/net/tun -v /opt/zerotier:/var/lib/zerotier-one zerotier/zerotier:latest
-
部署 UI
docker run -d --name ztncui --restart always \ -e MYADDR={服务器IP} \ -e HTTP_PORT=4000 \ -e HTTP_ALL_INTERFACES=yes \ -e ZT_ADDR={zerotier地址, 比如Docker网关:9993} \ -e ZT_TOKEN={可以为空,但需要挂载zerotier-one的配置路径} \ -v /opt/ztncui:/opt/ztncui/etc \ -v /opt/zerotier:/var/lib/zerotier-one \ -p 4000:4000 \ honmaple/ztncui:latest
ZT_ADDR: 由于 zerotier 和 ztncui 没有部署在一个容器,所以需要从UI内部访问宿主机的 9993 端口,这里可以使用UI容器的网关访问,比如UI容器的IP是 172.17.0.12,则访问 172.17.0.1
另外,zerotier 默认的API接口只允许 127.0.0.1 访问,所以需要在挂载目录
/opt/zerotier
下新建一个 local.conf{ "settings": { "allowManagementFrom": ["127.0.0.1/24", "::1", "172.17.0.1/24"] } }
-
修改归属的用户和用户组
docker exec -it zerotier bash cd /var/lib/zerotier-one chown zerotier-one:zerotier-one local.conf exit
-
生成私有Planet文件
git clone https://github.com/honmaple/ztncui-aio --depth=1 cd ztncui-aio docker cp script/mkmoonworld-x86_64 zerotier:/tmp docker cp script/patch.sh zerotier:/tmp docker exec -it zerotier bash /tmp/patch.sh {服务器IP}
-
重启
docker restart zerotier
这样就能使私有Planet和zerotier客户端共存,让Planet服务器也能加入到内网环境了
组网教程
创建网络
-
使用浏览器打开UI管理界面
{服务器公网IP}:4000
,honmaple/ztncui
默认用户名密码是admin,password
-
添加一个内网网段,记得这个内网网段不能和需要加入组网的设备网段相同,比如我的设备C网段是
192.168.31.0/24
,就不能添加该网段,另外Docker所使用的网段172.0.0.0/8
也需要避免添加,所以我这里选择10.8.230.0/24
。不同的设备内网网段不同,请根据实际添加
加入网络
创建好网络后就会得到一串网络ID,登录到设备,然后使用
docker exec zerotier zerotier-cli join {网络ID}
加入网络,正常情况下会得到
200 join OK
刷新管理界面就会出现一个新的成员
然后勾选 Authorizerd 允许加入,再次刷新,就能看到该设备分配了一个新的IP 10.8.230.170
跨网段访问
什么是跨网段访问? 比如现在我可以通过 10.8.230.0/24 访问已经加入组网的设备,但我想要在设备B上访问我家里的其它设备,但是,我家里设备的网段是 192.168.31.0/24,正常是无法访问的,只能访问已经加入组网的Nas。这时需要配置静态路由,让设备B访问 192.168.31.0/24 网段时走zerotier配置好的IP。
如果手动添加就是
ip route add 192.168.31.0/24 via 10.8.230.170 dev {zerotier建立的网卡}
当然,也可以直接使用zerotier管理界面添加,选择 Routes
Target 输入想要访问的网段:192.168.31.0/24
,Gateway 输入之前分配的IP:10.8.230.170
。
创建好后可以在设备B上执行
ping 192.168.31.XX(除设备C之外的内网设备IP)
查看网络是否连通
安全限制
正因为跨网段访问只需要添加一个静态路由,就能访问我家里的其它设备,这无疑是非常不安全的。如果私有Planet服务器遭到入侵,我家里的所有联网设备都会暴露出去,即使加入组网只是其中的一台。基于此原因,我专门调整了一下zerotier的部署方式,不再使用 host网络 的方式部署,而是创建一个新的Docker网络 zerotier
docker network create --driver=bridge --subnet=192.168.100.0/24 --gateway=192.168.100.1 zerotier
注: 192.168.100.0/24
是一个全新的网段,不要使用172网段
然后删除之前部署的 zerotier 客户端,并使用 zerotier网络 重新部署
docker stop zerotier docker rm zerotier docker run -d --name zerotier --restart always --net zerotier --cap-add NET_ADMIN --device /dev/net/tun -v /opt/zerotier:/var/lib/zerotier-one zerotier/zerotier:latest
细心的朋友应该会发现我这里没有将 9993 端口映射给宿主机,这是由于我测试发现两台设备只需要其中一台开放 9993
端口,两台设备之间就能直连。如果两台设备都不开放端口,则会通过开放了端口的其它设备进行跳转,查看 peers 会看到一直是 RELAY 状态
root@cf5f973bd294:/# zerotier-cli peers 200 peers <ztaddr> <ver> <role> <lat> <link> <lastTX> <lastRX> <path> xxxxxxxxx 1.12.1 LEAF -1 RELAY
这时想要从设备B访问我家里其它联网的设备已是不可能,除非突破Docker的限制。而正常情况下,我想要从设备B上访问的是部署在设备C的其它服务(以Docker服务为主),所以,现在可以添加一个新的路由 192.168.100.0/24 指向 10.8.230.170,然后修改其它镜像使用的网络为 zerotier
docker run -d --rm --name=test-nginx --net=zerotier nginx:stable-alpine docker exec -it test-nginx ip a
接着在设备B上执行
ping 192.168.100.3(test-nginx的IP) curl 192.168.100.3
如果无法访问,需要在Docker所在宿主机上添加路由
ip route add 10.8.230.0/24 via 192.168.100.2(zerotier客户端的IP)
另外,由于Docker的IP可能会发生改变,除创建容器时指定 --ip
外,还可以将服务的端口映射出去,比如 NasTools 使用端口为 3000,那么可以在创建容器时指定
-p 11300:3000
然后在设备B上访问 192.168.100.1:11300
,即网关地址+映射的端口,这样就能避免Docker重启后IP发生改变而导致服务异常的情况
FAQ
如何修改默认的9993端口?
在 zerotier 挂载的目录下新建一个 local.conf
文件,并设置
{ "settings": { "primaryPort": 9995 } }