Zerotier笔记


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 为例

  1. 创建目录

    mkdir /opt/zerotier /opt/ztncui
  2. 部署服务

    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的目的:

  1. 官方的服务器基本都位于国外或者香港,服务连通性无法得到保证

  2. 安全性。试想一个陌生的设备加入到网络,而这个设备的许可只需要得到官方的认证即可。当然,官方是基本不可能发生这样的情况,但如果有一个完全控制的网络,何乐而不为呢

如何生成私有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的机器也加入到内网,大概是可以分为下面几种方式:

  1. (不推荐) 修改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
  2. 部署两个zerotier: 除了ztncui容器内部的一个zerotier,再在机器上部署一个客户端,并修改端口,避免端口冲突

  3. (推荐) ztncui镜像的UI和zerotier分开部署
    我研究后才发现 ztncui 的相关镜像把事情弄的很复杂,都把 ztncuizerotier 放到同一个镜像,专门去连接 localhost:9993 。其实是可以把两个镜像分开的,UI 只做 UI ,使用 API 去连接 zerotier 官方的镜像

UI和Zerotier分开部署

如果想要自己构建Docker镜像,可以参考 honmaple/ztncui-aio

  1. 部署 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
  2. 部署 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: 由于 zerotierztncui 没有部署在一个容器,所以需要从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"]
        }
    }
  3. 修改归属的用户和用户组

    docker exec -it zerotier bash
    cd /var/lib/zerotier-one
    chown zerotier-one:zerotier-one local.conf
    exit
  4. 生成私有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}
  5. 重启

    docker restart zerotier

    这样就能使私有Planet和zerotier客户端共存,让Planet服务器也能加入到内网环境了

组网教程

创建网络

  1. 使用浏览器打开UI管理界面 {服务器公网IP}:4000honmaple/ztncui 默认用户名密码是 admin,password

  2. 点击 Add network,输入一个网络名称,比如 testlab。然后选择 Easy setup

  3. 添加一个内网网段,记得这个内网网段不能和需要加入组网的设备网段相同,比如我的设备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

返回设备,可以看到设备多了一个新的IP

跨网段访问

什么是跨网段访问? 比如现在我可以通过 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/24Gateway 输入之前分配的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
    }
}

参考资料

作者: honmaple
链接: https://honmaple.me/articles/2023/09/zerotier-note.html
版权: CC BY-NC-SA 4.0 知识共享署名-非商业性使用-相同方式共享4.0国际许可协议
wechat
alipay

加载评论