ZeroTier是一款好用的P2P虚拟局域网开源软件,通过它可以实现外网到内网设备的访问。本文从服务端到客户端一条龙搭建一个简单的ZeroTier虚拟局域网,实现从外网对内网树莓派的访问。


ZeroTier的优点有:

  • 非常容易配置,只要拿到虚拟网络的ID,就可以加入网络,并自动分配IP地址,对小白具有亲和力。
  • 虚拟网络内的设备端对端建立连接,不需要经过中转服务器,响应快,不受服务器带宽、流量限制。

但其缺点也很明显,其官方的服务器位于国外,直连状态下容易打洞失败,这样第二条优点便无法体现。

为了改善使用体验,我们可以通过搭建moon服务器进行加速,或者也可以直接建一个行星服务器(planet),来实现自己的ZeroTier服务。

前置条件

  • 一台拥有公网IP的服务器
  • 服务器上有docker、docker-compose(因为我后面的操作就是通过docker的,非docker部署法请自行谷歌)

服务端安装

因为有大佬开源的docker镜像keynetworks/ztncui,因此安装的过程比较方便,但该镜像默认只提供一个管理平台,若直接使用该镜像而不加以任何修改,则并不能提供planet、moon服务器的作用,那就相当于白搭了,没有任何的意义。修改过程来自于此issue,本人只是在自己博客上记录一下以防忘记。

修改docker-compose文件

首先,新建一个文件夹,并创建docker-compose.yml文件。

mkdir zerotier-planet && cd zerotier-planet && vi docker-compose.yml

作为根服务器,需要对外开放9993的tcp与udp端口,因此需要在docker-compose文件里加上端口映射并打开服务器防火墙的9993端口(tcp/udp),同时,将MYADDR的值改为服务器的公网ip(不写或许也行):

version: '2.0'
services:
    ztncui:
        container_name: ztncui
        restart: always
        environment:
            # - MYADDR=公网地址(不填自动获取)
            - MYADDR=x.x.x.x
            - HTTP_PORT=3443
            - HTTP_ALL_INTERFACES=yes
            - ZTNCUI_PASSWD=password
        ports:
            - '3443:3443'
            - '9993:9993'
            - '9993:9993/udp'
        volumes:
            - './zerotier-one:/var/lib/zerotier-one'
            - './ztncui/etc:/opt/key-networks/ztncui/etc'
        image: keynetworks/ztncui

启动容器

docker-compose up -d
docker exec -it ztncui bash  # 进入容器

生成moon文件

cd /var/lib/zerotier-one
# 生成moon配置文件
zerotier-idtool initmoon identity.public > moon.json
chmod 777 moon.json
vi moon.json

若容器内没有vim,可在宿主机编辑文件(宿主机上有容器内的路径挂载)。

"stableEndpoints": ["127.0.0.1/9993"]中的本地ip修改为公网ip。

如果将服务器作为moon使用,则需要继续在容器内执行下面命令生成moon文件:

zerotier-idtool genmoon moon.json
mkdir moons.d
cp *.moon moons.d/

生成planet文件

如果将服务器作为planet使用,则需要进行下面的步骤。

回到容器外,下载此可执行文件,放置于moon.json相同路径下,执行命令:

chmod +x mkmoonworld-x86_64
./mkmoonworld-x86_64 moon.json
mv world.bin planet

即可生成planet文件,将此文件复制一份到容器内:

docker cp planet ztncui:/var/lib/zerotier-one

重启容器,服务端配置完成。

docker restart ztncui

配置虚拟网络

打开服务器3443端口后,在浏览器访问http 3443端口即可进入网站。


默认用户名和密码分别是:admin与password,在登录以后修改默认密码。

然后选择Add network,为我们的虚拟网络随便取一个名。因为我用的是阿里云的服务器,因此取名为了aliyun-net。然后我们选择Easy setup,进行网段的配置:


网段配置比较随意,怎么开心怎么配,但我认为使用一些不常用的网段会比较好,我这里配置了10.10.10.0/24网段。(然而10.10.10.0/24也并不算少见,例如我有一次连上朋友家WiFi以后发现无法通过ZeroTier访问实验室的服务器,搞了半天发现原来他们家WiFi内网网段居然也是10.10.10.0/24。。)

如此一来,最基本的配置过程已经结束。接下来只需要下载客户端以接入我们的虚拟网络。

客户端配置

ZeroTier在大部分操作系统上都有对应的客户端软件,非常方便,这里我在树莓派上安装,只需要一条命令:

curl -s https://install.zerotier.com/ | sudo bash

安装完成后,我们将前面生成的planet文件放到树莓派的/var/lib/zerotier-one/目录下,替换原有的planet,并重启zerotier-one服务,执行命令zerotier-cli listpeers,如果列出的条目中只有一条ip为前面设置的服务器公网ip的planet,就意味着planet文件生效了,接下来可以执行下面命令加入虚拟网络:

sudo zerotier-cli join [network ID]

稍等片刻,我们可以在前面的服务端网站上发现一个新的member,为其勾选Authorized,即可让它加入虚拟网络,我们可以为其手动或自动分配一个IP地址。


如上图,在其他加入该网络的设备上,访问IP地址10.10.10.2即可访问到我的树莓派。后面文章将介绍如何通过在OpenWrt路由器上配置ZeroTier与防火墙规则以实现外网访问整个局域网。


当然,自建行星服务器也有缺陷,例如手机端的软件目前不支持自行导入planet文件(iOS系统上的ZeroTier软件甚至连moon文件都无法自行配置),如果有手机使用ZeroTier的需求,建议还是自建moon节点进行转发。

将上述Planet服务器作为Moon的方法

首先,我们不需要手动修改docker容器里的planet文件,也即不需要执行前面的这一步:

docker cp planet ztncui:/var/lib/zerotier-one

如果执行过了,进入容器(或在本地挂载目录下)将planet文件删去,然后重启此docker容器。

同理,客户端的zerotier配置目录下(Ubuntu下是/var/lib/zerotier-one/)不需要手动修改planet文件,如果修改了,则删去。然后,在客户端的zerotier配置目录下创建moons.d目录,并将前面生成的moon文件复制到里面。最后重启zerotier服务。

在客户端终端执行

zerotier-cli listpeers

若能看到MOON节点,则表示配置成功。