0. 真实业务场景背景
- A 端物理网段:
10.0.0.0/24(组网网关虚拟 IP:198.18.0.223) - B 端物理网段:
172.16.200.0/22(组网网关虚拟 IP:198.18.0.162) - 核心需求:两地局域网内所有设备免装客户端,直接通过内网物理 IP 互访对端局域网。
- 安全合规:为规避全网扫描和运营商 UDP 阻断,需将默认通信端口
9993修改为自定义的19993
一、 服务端自建部署(云服务器端)
准备一台带公网 IP 的服务器,在安全组/防火墙中放行以下端口:
- TCP 4000:Web 管理控制台
- TCP 3180:Planet 配置文件在线下载端口
- UDP 19993 与 TCP 19993:ZeroTier 核心通信与握手端口默认9993(UDP 必须开放)
1. 编写 docker-compose.yml
在宿主机新建目录并创建配置文件,注意将宿主机映射端口修改为自定义的 19993:
yaml
version: '2.0'
services:
ztncui:
container_name: ztncui
restart: always
environment:
- MYADDR=你的服务器公网IP # 👈 改成自己的服务器公网IP
- HTTP_PORT=4000
- HTTP_ALL_INTERFACES=yes
- ZTNCUI_PASSWD=your_secure_password # 👈 改成你的网页初始密码
ports:
- '4000:4000' # Web 控制台入口
- '19993:9993' # 核心通信 TCP
- '19993:9993/udp' # 核心通信 UDP(极重要)
- '3180:3180' # planet 文件在线下载入口
volumes:
- './zerotier-one:/var/lib/zerotier-one'
- './ztncui/etc:/opt/key-networks/ztncui/etc'
image: keynetworks/ztncui
执行启动命令:
docker-compose up -d
2. 攻克底层硬伤:修改脚本实现自定义端口
由于该开源项目依赖的二进制编译补丁 mkmoonworld 存在硬编码缺陷,无法直接读取外部端口变量。我们必须直接强行修改容器内 patch.sh 脚本的源码:
# 1. 下载这两个文件拷贝到容器内(请确保宿主机当前目录下有这两个项目文件)
docker cp mkmoonworld-x86_64 ztncui:/tmp
docker cp patch.sh ztncui:/tmp
# 2. 核心避坑:用 sed 强行将脚本内写死的 9993 端口替换为你的自定义端口 19993
docker exec -it ztncui sed -i 's/9993/19993/g' /tmp/patch.sh
# 3. 清理之前可能存在的旧 planet 残留编译文件
rm -rf ./ztncui/etc/myfs/*
# 4. 重新执行修改后的编译注入脚本
docker exec -it ztncui bash /tmp/patch.sh
# 5. 重启容器使带有 19993 端口彻底生效
docker restart ztncui
二、 网页控制台(ztncui)初始化配置
- 浏览器访问
http://你的服务器公网IP:4000。 - 输入用户名
admin,初始密码为你在 Compose 中设置的your_secure_password(首次登录会强制要求修改密码)。 - 点击 Add network 创建一个全新的私有网络,系统会生成一个 16 位的 Network ID(例如
8a123456789abcde)。 - 点进该网络详情,在 Easy Setup 中规划 ZeroTier 的虚拟 IP 地址池(例如:选择
198.18.0.0/16)。
三、 客户端部署与组网
由于变更了默认端口,所有客户端必须使用带有新端口基因的 planet 文件进行配置。
1. 获取专属 planet 文件
直接在任意浏览器中访问:http://你的服务器公网IP:3180/planet,下载该二进制引导文件。
2. Linux 网关设备(或 OpenWrt 路由器)配置
# 1. 安装官方客户端
curl -s https://install.zerotier.com | sudo bash
# 2. 停止服务
sudo systemctl stop zerotier-one
# 3. 将下载好的私有 planet 文件覆盖到系统路径中
sudo cp ./planet /var/lib/zerotier-one/planet
# 4. 核心避坑:如果是换端口/换网络,必须顺手清理本地的旧节点缓存
cd /var/lib/zerotier-one/
sudo rm -rf peers.d/ networks.d/
# 5. 重新启动服务
sudo systemctl start zerotier-one
# 6. 加入你全新的 16 位网络 ID
sudo zerotier-cli join 你的16位NetworkID
3. Windows 客户端(或个别员工电脑)配置
- 安装官方 Windows 客户端。https://www.zerotier.com/download/
- 按下
Win + R输入services.msc,找到 ZeroTier One 服务并选择“停止”。 - 进入文件夹:
C:\ProgramData\ZeroTier\One\。 - 将下载的新
planet文件覆盖替换到该目录下,并彻底删除peers.d和networks.d两个缓存文件夹。 - 在服务管理器中重新“启动” ZeroTier One 服务。
- 以管理员身份打开 PowerShell,执行加网:
zerotier-cli join 你的16位NetworkID。
4. 验证直连状态(判定成功标准)
在任意客户端命令行运行:zerotier-cli peers
判定标准:必须看到角色为 PLANET 的那一行,其后的连接路径清晰显示为 你的服务器公网IP/19993,且末尾的状态必须为 DIRECT(直连)。如果显示为 RELAY 且底部有黄色 UDP 警告,说明云服务器安全组的 UDP 19993 端口未成功开放。
5、 高级路由打通(核心重点)
当多地网关加入网络后,需要通过“双向双层路由”让整个局域网彻底合体。
1:控制台授权与开启大二层桥接
- 登录 4000 网页后台,在 Members 列表中会看到 A 端和 B 端的网关设备。
- 勾选 Authorized 允许加入。此时 A 网关获取虚拟 IP
198.18.0.223,B 网关获取虚拟 IP198.18.0.162。 
- 点击两个网关右侧的 🔧 设置图标,务必勾选 “Allow Bridging”(允许桥接)。如果你需要网络发现,这是共享打印机大二层广播和网络邻居自动刷新的技术根基。
6、控制台配置静态路由
在 4000 后台的 Routes 区域,告诉 ZeroTier 两边的物理网段往哪走:
- 去往 A 端:Target 填
10.0.0.0/24── Via 填A端客户端IP198.18.0.223 - 去往 B 端:Target 填
172.16.200.0/22── Via 填B端客户端IP198.18.0.162
7、开启网关系统的 IP 转发
在 A 端和 B 端的 Linux 网关上分别执行以下命令,允许其代传局域网流量,并将其永久固化(防止重启失效):
# 临时开启转发
sudo sysctl -w net.ipv4.ip_forward=1
# 永久固化配置
echo "net.ipv4.ip_forward = 1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
四:配置企业本地物理主路由器
由于其他设备未安装客户端软件,当 A 端的电脑寻找 172.16.200.X 时,它们会把流量丢给本地的物理主路由器。因此必须在多地端的核心物理路由器后台添加静态路由:
在 A 端的主路由器后台添加:
- 目的网络:
172.16.200.0 - 子网掩码:
255.255.252.0(即/22) - 下一跳/网关:填 A 端内运行客户端的内网 IP(例如
10.0.0.X)。
在 B 端的主路由器后台添加:
目的网络:10.0.0.0
子网掩码:255.255.255.0 (即 /24)
下一跳/网关:填 B 端内运行客户端的内网 IP(例如 172.16.200.X)。
五、 最终业务效果检验
配置完成后,可以进行测试:
- SMB 测速:在 A 端任意电脑的资源管理器地址栏输入
\\172.16.200.X,即可无感直连 B 端的物理服务器,大文件读写直接拉满两端的宽带上行上限。 - 打印机测试:点击 Windows 的“添加设备与打印机”,网络邻居会通过 mDNS/WSD 广播自动跨地域“刷出”异地办公室的共享打印机,直接点击安装即可,无需繁琐的手动指定端口。
- 网页直接访问。
- ping测试。