From 5ed5cafcdcede9914aa9fc7cb8b471e83675199a Mon Sep 17 00:00:00 2001 From: Mohammad Kiani Date: Fri, 15 May 2026 14:42:53 +0330 Subject: [PATCH] init --- .github/workflows/zerotier-planet-builder.yml | 26 ++++ Dockerfile | 44 +++++++ LICENSE | 21 ++++ README.md | 97 ++++++++++++++ init.sh | 23 ++++ patch/mkworld.cpp | 119 ++++++++++++++++++ patch/patch.json | 5 + patch/patch.py | 51 ++++++++ 8 files changed, 386 insertions(+) create mode 100644 .github/workflows/zerotier-planet-builder.yml create mode 100644 Dockerfile create mode 100644 LICENSE create mode 100644 README.md create mode 100644 init.sh create mode 100644 patch/mkworld.cpp create mode 100644 patch/patch.json create mode 100644 patch/patch.py diff --git a/.github/workflows/zerotier-planet-builder.yml b/.github/workflows/zerotier-planet-builder.yml new file mode 100644 index 0000000..63cea61 --- /dev/null +++ b/.github/workflows/zerotier-planet-builder.yml @@ -0,0 +1,26 @@ +name: zerotier-planet-builder + +on: + workflow_dispatch + +jobs: + + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Edit the planet IP + run: sed -i "s/1.1.1.1/${{ secrets.IP }}/g" ./patch/patch.json + - name: Edit username and password + run: sed -i "s/admin/${{ secrets.USERNAME }}/g" ./init.sh && sed -i "s/zero-ui/${{ secrets.PASSWORD }}/g" ./init.sh + - name: Build the Zerotier Planet Docker image + run: docker build . --file Dockerfile --tag zerotier-planet + - name: install 7zip + run: sudo apt-get -qq -y install p7zip-full + - name: Save the Docker image + run: docker save zerotier-planet|gzip > zerotier-planet.tar.gz && 7z a -t7z -mx=9 -p${{ secrets.PASSWORD }} zerotier-planet.tar.gz.7z zerotier-planet.tar.gz + - name: Upload the Docker image + uses: actions/upload-artifact@v4 + with: + name: zerotier-planet.tar.gz.7z + path: zerotier-planet.tar.gz.7z diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..715d6ed --- /dev/null +++ b/Dockerfile @@ -0,0 +1,44 @@ +FROM node:lts-bullseye-slim AS build-planet +LABEL stage=tmp + +RUN echo "download tools and code..." && \ + apt-get -qq update && \ + apt-get -qq -y install git python3 make curl wget g++ gnupg +RUN mkdir -p /usr/include/nlohmann/ && \ + cd /usr/include/nlohmann/ && \ + wget https://github.com/nlohmann/json/releases/download/v3.10.5/json.hpp +RUN cd /opt && \ + git clone -v https://github.com/zerotier/ZeroTierOne.git --depth 1 + +RUN echo "install zerotier..." && \ + curl -s https://install.zerotier.com | bash > /dev/null && \ + cd /var/lib/zerotier-one && zerotier-idtool initmoon identity.public >moon.json +ADD ./patch /app/patch +ARG planet +RUN cd /app/patch && \ + python3 patch.py && \ + cd /var/lib/zerotier-one && \ + zerotier-idtool genmoon moon.json && \ + mkdir moons.d && \ + cp ./*.moon ./moons.d +RUN echo "compile planet..." && \ + cd /opt/ZeroTierOne/attic/world/ && sh build.sh > /dev/null && \ + cd /opt/ZeroTierOne/attic/world/ && ./mkworld > /dev/null && \ + mkdir /app/bin -p && cp world.bin /app/bin/planet && \ + cp /app/bin/planet /var/lib/zerotier-one/planet + +FROM node:lts-bullseye-slim +COPY --from=build-planet /var/lib/zerotier-one/ /var/lib/zerotier-one/ +COPY --from=build-planet /usr/sbin/zero* /usr/bin/ +COPY --from=build-planet /usr/lib/x86_64-linux-gnu/libssl* /usr/lib/x86_64-linux-gnu/ +COPY --from=build-planet /usr/lib/x86_64-linux-gnu/libcrypto* /usr/lib/x86_64-linux-gnu/ +RUN true +COPY --from=dec0dos/zero-ui:latest /app/ /app/ +COPY init.sh / +RUN chmod +x /init.sh +EXPOSE 9993/udp +EXPOSE 4000/tcp +ENV NODE_ENV=production +ENV ZU_SERVE_FRONTEND=true +#VOLUME /var/lib/zerotier-one/controller.d /app/backend/data +ENTRYPOINT ["/init.sh"] \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..ee926a9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 kissshot + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..9744ba6 --- /dev/null +++ b/README.md @@ -0,0 +1,97 @@ +# zerotier-planet-builder +[中文说明](#中文说明) +A ZeroTierOne planet with zero-ui web interface builder. +Easier, faster and smaller way to create your private zerotier controller container. +Inspired by [docker-zerotier-planet](https://github.com/xubiaolin/docker-zerotier-planet) and [zero-ui](https://github.com/dec0dOS/zero-ui). +## How to use +- 1 . Fork this repository. +- 2 . Go to Setting - Secrets - Actions , add secrects: +>IP : your planet server IP. +USERNAME: zero-ui username. +PASSWORD: zero-ui password and docker image password. + +![secrets.png](https://s2.loli.net/2022/08/29/uxcTpePls5SmbWn.png) +- 3 . Go to Actions,click "Run workflow." +![run.png](https://s2.loli.net/2022/08/29/ITs4SVxLE9lORM3.png) +- 4 . Wait 3 minutes and you will see the Artifacts below, download it. +![artifacts.png](https://s2.loli.net/2022/08/29/Gc3fbyUwZReJOHt.png) +- 5 . Use the password you set to unzip it to get **zerotier-planet.tar.gz** and upload it to your server. +Prepare the docker environment on your server and run the following command to import the image: +```sh +docker image load < zerotier-planet.tar.gz +``` +Check your image: +```sh +docker images +``` +Run docker: +```sh +docker run -d --name zerotier-server -p 4000:4000 -p 9993:9993/udp zerotier-planet +``` +Or, if you want to mount the data to the host path +```sh +docker run -d --name zerotier-server -p 4000:4000 -p 9993:9993/udp -v /data/zerotier:/var/lib/zerotier-one/controller.d -v /data/zero-ui/:/app/backend/data zerotier-planet +``` +Note that each run of the docker image produces a unique ID related file. If you create a new docker image, you need to copy the related files under/var/lib/zerotier-one under the original image. +```sh + docker cp zerotier-server:/var/lib/zerotier-one backup +``` +Open http://IP:4000, use your secrets USERNAME and PASSWORD to login. +## For client +Replace your planet file: +Download your planet: http://IP:4000/app/planet + +Windows: C:\ProgramData\ZeroTier\One\planet +Linux: /var/lib/zerotier-one/planet +Macos: /Library/Application\ Support/ZeroTier/One/planet +Andriod: https://github.com/kaaass/ZerotierFix + +**Note: Restart zerotier client related services after replacing the planet file.** + +# 中文说明 +一个zerotier planet docker生成器,轻松搭建属于你自己的zerotier服务器,目的是生成更简单,更快和更小的docker镜像。 +本项目参考自 [docker-zerotier-planet](https://github.com/xubiaolin/docker-zerotier-planet) 和 [zero-ui](https://github.com/dec0dOS/zero-ui),关于zerotier planet的概念和用途、客户端文件替换的配置,[docker-zerotier-planet](https://github.com/xubiaolin/docker-zerotier-planet)这个项目描述的很详细,本项目web端使用[zero-ui](https://github.com/dec0dOS/zero-ui),更详尽的web端配置可以点进该项目查看进阶使用指南。 + +## 怎么使用 +- 1 . Fork 这个项目. +- 2 . 点击你项目的 Setting - Secrets - Actions , 添加 secrects: +>IP : 你的 planet 服务端 IP,就是公网IP +USERNAME: 登陆zero-ui的用户名 +PASSWORD: zero-ui 的密码,和docker的镜像压缩包密码. + +![secrets.png](https://s2.loli.net/2022/08/29/uxcTpePls5SmbWn.png) +- 3 . 点击 Actions,点击 "Run workflow." +![run.png](https://s2.loli.net/2022/08/29/ITs4SVxLE9lORM3.png) +- 4 . 等待三分钟左右,就可以下载docker镜像了,大小在100M以内. +![artifacts.png](https://s2.loli.net/2022/08/29/Gc3fbyUwZReJOHt.png) +- 5 . 用你之前设置的密码解压文件得到 **zerotier-planet.tar.gz** 并上传到服务器. +在你的服务器准备docker运行环境,运行以下命令导入镜像: +```sh +docker image load < zerotier-planet.tar.gz +``` +检查镜像是否导入成功: +```sh +docker images +``` +运行docker: +```sh +docker run -d --name zerotier-server -p 4000:4000 -p 9993:9993/udp zerotier-planet +``` +或者,如果你想把数据挂在到主机目录,以便容器损坏的时候迁移: +```sh +docker run -d --name zerotier-server -p 4000:4000 -p 9993:9993/udp -v /data/zerotier:/var/lib/zerotier-one/controller.d -v /data/zero-ui/:/app/backend/data zerotier-planet +``` +注意每次运行docker镜像生产唯一的id相关文件,如果你建立新docker镜像的话,你需要复制原来镜像下/var/lib/zerotier-one下的相关文件 +```sh + docker cp zerotier-server:/var/lib/zerotier-one backup +``` +打开 http://IP:4000, 用你设置的secrets USERNAME 和 PASSWORD 登陆. +## 客户端 +替换planet文件: +下载planet: http://IP:4000/app/planet + +Windows: C:\ProgramData\ZeroTier\One\planet +Linux: /var/lib/zerotier-one/planet +Macos: /Library/Application\ Support/ZeroTier/One/planet +Andriod: https://github.com/kaaass/ZerotierFix +**注意替换planet文件后重启zerotier客户端相关服务.** diff --git a/init.sh b/init.sh new file mode 100644 index 0000000..4a88d3e --- /dev/null +++ b/init.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env sh + +if [ -z "$ZU_SECURE_HEADERS" ] +then export ZU_SECURE_HEADERS=false +fi + +if [ -z "$ZU_DEFAULT_USERNAME" ] +then export ZU_DEFAULT_USERNAME=admin +fi + +if [ -z "$ZU_DEFAULT_PASSWORD" ] +then export ZU_DEFAULT_PASSWORD=zero-ui +fi + +cp /var/lib/zerotier-one/planet /app/frontend/build/planet +js=$(grep -ors "Please Log In to continue" /app|cut -d":" -f1) +sed -i "s/Please Log In to continue/\/app\/planet /g" $js +sed -i "s/ZeroUI - ZeroTier Controller Web UI - is a web user interface for a self-hosted ZeroTier network controller./Download planet:/g" $js +echo Run zerotier... +zerotier-one -d +cd /app/backend/ +echo Run zero ui... +node ./bin/www diff --git a/patch/mkworld.cpp b/patch/mkworld.cpp new file mode 100644 index 0000000..49181a7 --- /dev/null +++ b/patch/mkworld.cpp @@ -0,0 +1,119 @@ +/* + * ZeroTier One - Network Virtualization Everywhere + * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * This utility makes the World from the configuration specified below. + * It probably won't be much use to anyone outside ZeroTier, Inc. except + * for testing and experimentation purposes. + * + * If you want to make your own World you must edit this file. + * + * When run, it expects two files in the current directory: + * + * previous.c25519 - key pair to sign this world (key from previous world) + * current.c25519 - key pair whose public key should be embedded in this world + * + * If these files do not exist, they are both created with the same key pair + * and a self-signed initial World is born. + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace ZeroTier; + +int main(int argc,char **argv) +{ + std::string previous,current; + if ((!OSUtils::readFile("previous.c25519",previous))||(!OSUtils::readFile("current.c25519",current))) { + C25519::Pair np(C25519::generate()); + previous = std::string(); + previous.append((const char *)np.pub.data,ZT_C25519_PUBLIC_KEY_LEN); + previous.append((const char *)np.priv.data,ZT_C25519_PRIVATE_KEY_LEN); + current = previous; + OSUtils::writeFile("previous.c25519",previous); + OSUtils::writeFile("current.c25519",current); + fprintf(stderr,"INFO: created initial world keys: previous.c25519 and current.c25519 (both initially the same)" ZT_EOL_S); + } + + if ((previous.length() != (ZT_C25519_PUBLIC_KEY_LEN + ZT_C25519_PRIVATE_KEY_LEN))||(current.length() != (ZT_C25519_PUBLIC_KEY_LEN + ZT_C25519_PRIVATE_KEY_LEN))) { + fprintf(stderr,"FATAL: previous.c25519 or current.c25519 empty or invalid" ZT_EOL_S); + return 1; + } + C25519::Pair previousKP; + memcpy(previousKP.pub.data,previous.data(),ZT_C25519_PUBLIC_KEY_LEN); + memcpy(previousKP.priv.data,previous.data() + ZT_C25519_PUBLIC_KEY_LEN,ZT_C25519_PRIVATE_KEY_LEN); + C25519::Pair currentKP; + memcpy(currentKP.pub.data,current.data(),ZT_C25519_PUBLIC_KEY_LEN); + memcpy(currentKP.priv.data,current.data() + ZT_C25519_PUBLIC_KEY_LEN,ZT_C25519_PRIVATE_KEY_LEN); + + // ========================================================================= + // EDIT BELOW HERE + + std::vector roots; + + const uint64_t id = ZT_WORLD_ID_EARTH; + const uint64_t ts = 1567191349589ULL; // August 30th, 2019 + + //__PATCH_REPLACE__ + + // END WORLD DEFINITION + // ========================================================================= + + fprintf(stderr,"INFO: generating and signing id==%llu ts==%llu" ZT_EOL_S,(unsigned long long)id,(unsigned long long)ts); + + World nw = World::make(World::TYPE_PLANET,id,ts,currentKP.pub,roots,previousKP); + + Buffer outtmp; + nw.serialize(outtmp,false); + World testw; + testw.deserialize(outtmp,0); + if (testw != nw) { + fprintf(stderr,"FATAL: serialization test failed!" ZT_EOL_S); + return 1; + } + + OSUtils::writeFile("world.bin",std::string((const char *)outtmp.data(),outtmp.size())); + fprintf(stderr,"INFO: world.bin written with %u bytes of binary world data." ZT_EOL_S,outtmp.size()); + + fprintf(stdout,ZT_EOL_S); + fprintf(stdout,"#define ZT_DEFAULT_WORLD_LENGTH %u" ZT_EOL_S,outtmp.size()); + fprintf(stdout,"static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {"); + for(unsigned int i=0;i 0) + fprintf(stdout,","); + fprintf(stdout,"0x%.2x",(unsigned int)d[i]); + } + fprintf(stdout,"};" ZT_EOL_S); + + return 0; +} \ No newline at end of file diff --git a/patch/patch.json b/patch/patch.json new file mode 100644 index 0000000..7b26e01 --- /dev/null +++ b/patch/patch.json @@ -0,0 +1,5 @@ +{ + "stableEndpoints": [ + "1.1.1.1/9993" + ] +} diff --git a/patch/patch.py b/patch/patch.py new file mode 100644 index 0000000..3f4fe7c --- /dev/null +++ b/patch/patch.py @@ -0,0 +1,51 @@ +import os +import json +from re import M + + +def get_moon(): + with open("/var/lib/zerotier-one/moon.json", "r") as f: + moon = json.load(f) + return moon + + +def get_patch(): + with open("/app/patch/patch.json", "r") as f: + return json.load(f) + + +def patch(): + moon = get_moon() + patch = get_patch() + + identity = moon["roots"][0]["identity"] + moon["roots"][0]["stableEndpoints"] = patch["stableEndpoints"] + + # 修改moon + with open("/var/lib/zerotier-one/moon.json", "w") as f: + f.write(json.dumps(moon,sort_keys=True, indent=2)) + + #print("修改后的moon") + #print(moon) + + # 修改world + moon["roots"][0]["stableEndpoints"] = get_patch()["stableEndpoints"] + text = f"""// Los Angeles + roots.push_back(World::Root()); + roots.back().identity = Identity("{identity}"); +""" + + for i in get_patch()["stableEndpoints"]: + text += f'\n roots.back().stableEndpoints.push_back(InetAddress("{i}"));' + + # 生成文件 + with open("/app/patch/mkworld.cpp", "r") as cpp: + world = "".join(cpp.readlines()) + world = world.replace("//__PATCH_REPLACE__", text) + + with open("/opt/ZeroTierOne/attic/world/mkworld.cpp", "w") as cpp: + cpp.write(world) + + +if __name__ == '__main__': + patch()