From 9a35e69c822ef39c6aa4a0ff7100155b87c44e85 Mon Sep 17 00:00:00 2001 From: wangdongpo <544209413@qq.com> Date: Sun, 22 Feb 2026 23:42:05 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=83=A8=E7=BD=B2=E8=84=9A?= =?UTF-8?q?=E6=9C=AC=EF=BC=8C=E5=A2=9E=E5=BC=BA=E9=94=99=E8=AF=AF=E5=A4=84?= =?UTF-8?q?=E7=90=86=E5=92=8C=E7=94=A8=E6=88=B7=E6=8F=90=E7=A4=BA=EF=BC=8C?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=20README=20=E6=96=87=E6=A1=A3=E4=BB=A5?= =?UTF-8?q?=E5=8F=8D=E6=98=A0=E6=9C=80=E6=96=B0=E7=9A=84=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 43 +++++++++++----- deploy-zerotier-aio.sh | 111 ++++++++++++++++++++++++++++++----------- 2 files changed, 114 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 10bfe94..e9053c0 100644 --- a/README.md +++ b/README.md @@ -9,28 +9,47 @@ └── zt-mkworld planet 生成目录(暂未使用) ## 快速部署 -1. 上传 zerotier-aio-zh.tar 到 /opt/zerotier-aio/ -2. chmod +x deploy-zerotier-aio.sh -3. sudo ./deploy-zerotier-aio.sh -4. 阿里云安全组放行:9993/udp、3000/tcp、3443/tcp +1. 将 `deploy-zerotier-aio.sh` 和 `zerotier-aio-zh.tar` 放到 `/opt/zerotier-aio/` +2. 执行: + ```bash + cd /opt/zerotier-aio + chmod +x deploy-zerotier-aio.sh + sudo ./deploy-zerotier-aio.sh + ``` +3. 阿里云安全组放行:`9993/udp`、`3000/tcp`、`3443/tcp` + +说明: +- 本脚本按阿里云环境优化,会优先从 `http://100.100.100.200/latest/meta-data/eipv4` 获取公网 IP。 +- 这是离线部署脚本,`zerotier-aio-zh.tar` 必须存在;不会依赖 Docker Hub 拉镜像。 ## 备份与迁移 备份: -tar -czf zerotier-aio-$(date +%Y%m%d).tar.gz /opt/zerotier-aio +```bash +tar -czf zerotier-aio-backup-$(date +%Y%m%d).tar.gz /opt/zerotier-aio +``` 新服务器恢复: -1. 解压到 /opt/zerotier-aio -2. 修改 docker-compose.yml 中的 MYADDR 为新公网 IP -3. 如果 Moon IP 变了,需要重新生成 Moon(删除 zerotier-one/moons.d 后重新运行脚本) -4. docker load -i zerotier-aio-zh.tar -5. docker compose up -d +1. 将备份包、`deploy-zerotier-aio.sh`、`zerotier-aio-zh.tar` 放到新服务器 `/opt/zerotier-aio/` +2. 运行脚本,脚本会自动恢复并按当前公网 IP 重写 `docker-compose.yml` +3. 如果是迁移且公网 IP 已变化,需要重新生成 Moon: + ```bash + FORCE_REGEN_MOON=1 sudo ./deploy-zerotier-aio.sh + ``` ## 客户端加入 1. 手动放置 Moon 文件 或 执行: + ```bash zerotier-cli orbit -2. zerotier-cli join <网络ID> + ``` +2. 执行: + ```bash + zerotier-cli join <网络ID> + ``` 3. Web 面板授权成员 -4. set <网络ID> allowManaged=1 +4. 按需开启托管路由: + ```bash + zerotier-cli set <网络ID> allowManaged=1 + ``` ## 注意事项 - 密码:admin123(首次登录立即修改) diff --git a/deploy-zerotier-aio.sh b/deploy-zerotier-aio.sh index 9944027..5d7630e 100644 --- a/deploy-zerotier-aio.sh +++ b/deploy-zerotier-aio.sh @@ -1,5 +1,5 @@ #!/bin/bash -set -e +set -Eeuo pipefail echo "======================================" echo " ZeroTier AIO 离线快速部署脚本 v2" @@ -8,47 +8,84 @@ echo "======================================" [ "$EUID" -ne 0 ] && { echo "请用 root 执行"; exit 1; } -# 安装依赖 -command -v docker &>/dev/null || { +INSTALL_DIR="/opt/zerotier-aio" +IMAGE_TAR="$INSTALL_DIR/zerotier-aio-zh.tar" +IMAGE_REF="niliaerith/zerotier-aio-zh:latest" +CONTAINER_NAME="zerotier-aio" +FORCE_REGEN_MOON="${FORCE_REGEN_MOON:-0}" + +if ! command -v apt >/dev/null 2>&1; then + echo "当前脚本仅支持 Debian/Ubuntu(需要 apt)" + exit 1 +fi + +# 安装依赖(离线环境至少要有 docker + compose + curl + ip) +if ! command -v docker >/dev/null 2>&1; then apt update -y - apt install -y docker.io docker-compose-plugin curl + apt install -y docker.io docker-compose-plugin curl iproute2 systemctl enable --now docker -} +fi + +if ! docker compose version >/dev/null 2>&1; then + apt update -y + apt install -y docker-compose-plugin +fi + +command -v curl >/dev/null 2>&1 || apt install -y curl +command -v ip >/dev/null 2>&1 || apt install -y iproute2 # 检查 TUN modprobe tun 2>/dev/null || true [ -c /dev/net/tun ] || { echo "TUN 不可用"; exit 1; } # 获取公网 IP -PUBLIC_IP=$(curl -s http://100.100.100.200/latest/meta-data/eipv4 || true) -[ -z "$PUBLIC_IP" ] && PUBLIC_IP=$(ip -4 addr show eth0 | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | head -n1) -[ -z "$PUBLIC_IP" ] && read -p "无法自动获取公网IP,请手动输入: " PUBLIC_IP +PUBLIC_IP=$(curl -fsS --connect-timeout 2 --max-time 5 http://100.100.100.200/latest/meta-data/eipv4 || true) +[ -z "$PUBLIC_IP" ] && PUBLIC_IP=$(ip route get 1.1.1.1 2>/dev/null | awk '/src/ {for(i=1;i<=NF;i++) if($i=="src"){print $(i+1); exit}}') +[ -z "$PUBLIC_IP" ] && read -r -p "无法自动获取公网IP,请手动输入: " PUBLIC_IP +[ -n "$PUBLIC_IP" ] || { echo "未获取到公网 IP,退出"; exit 1; } echo "公网 IP: $PUBLIC_IP" -INSTALL_DIR="/opt/zerotier-aio" mkdir -p "$INSTALL_DIR" cd "$INSTALL_DIR" # 如果有备份包,优先恢复 if ls zerotier-aio-backup*.tar.gz 1>/dev/null 2>&1; then - echo "检测到备份包,正在恢复..." - tar -xzf zerotier-aio-backup*.tar.gz -C /opt + BACKUP_FILE=$(ls -t zerotier-aio-backup*.tar.gz | head -n1) + echo "检测到备份包,正在恢复: $BACKUP_FILE" + tar -xzf "$BACKUP_FILE" -C /opt elif ls zerotier-aio-essential*.tar.gz 1>/dev/null 2>&1; then - tar -xzf zerotier-aio-essential*.tar.gz -C /opt + BACKUP_FILE=$(ls -t zerotier-aio-essential*.tar.gz | head -n1) + echo "检测到 essential 包,正在恢复: $BACKUP_FILE" + tar -xzf "$BACKUP_FILE" -C /opt +elif ls zerotier-aio-[0-9]*.tar.gz 1>/dev/null 2>&1; then + # 兼容旧版文档中的备份命名 + BACKUP_FILE=$(ls -t zerotier-aio-[0-9]*.tar.gz | head -n1) + echo "检测到旧版命名备份,正在恢复: $BACKUP_FILE" + tar -xzf "$BACKUP_FILE" -C /opt fi -# 加载镜像(如果 tar 存在) -[ -f zerotier-aio-zh.tar ] && { - echo "加载本地镜像..." - docker load -i zerotier-aio-zh.tar +# 加载镜像(离线强依赖) +[ -f "$IMAGE_TAR" ] || { + echo "未找到离线镜像包: $IMAGE_TAR" + echo "请先上传 zerotier-aio-zh.tar 到 $INSTALL_DIR" + exit 1 +} + +echo "加载本地镜像..." +docker load -i "$IMAGE_TAR" +docker image inspect "$IMAGE_REF" >/dev/null 2>&1 || { + echo "镜像加载后未找到: $IMAGE_REF" + echo "请确认 tar 内镜像标签与 docker-compose.yml 一致" + exit 1 } # 生成或使用 docker-compose.yml cat > docker-compose.yml </dev/null 2>&1; then + break + fi + sleep 1 +done +docker exec "$CONTAINER_NAME" test -f /var/lib/zerotier-one/identity.public >/dev/null 2>&1 || { + echo "容器未完成初始化,未找到 identity.public" + exit 1 +} # 检查 Moon(如果 moons.d 为空则生成) MOONS_DIR="./zerotier-one/moons.d" -if [ ! -d "$MOONS_DIR" ] || [ -z "$(ls -A "$MOONS_DIR")" ]; then + +if [ "$FORCE_REGEN_MOON" = "1" ]; then + rm -f "$MOONS_DIR"/*.moon 2>/dev/null || true +fi + +if [ ! -d "$MOONS_DIR" ] || [ -z "$(find "$MOONS_DIR" -maxdepth 1 -name '*.moon' -print -quit 2>/dev/null)" ]; then echo "生成 Moon..." - docker exec zerotier-aio zerotier-idtool initmoon /var/lib/zerotier-one/identity.public > /tmp/moon.json - sed -i "s|\"stableEndpoints\": \[\]|\"stableEndpoints\": [\"$PUBLIC_IP/9993\"]|" /tmp/moon.json - docker exec zerotier-aio bash -c "cd /tmp && zerotier-idtool genmoon moon.json" - MOON_FILE=$(docker exec zerotier-aio find /tmp -name "*.moon" | head -n1) + docker exec "$CONTAINER_NAME" sh -c "zerotier-idtool initmoon /var/lib/zerotier-one/identity.public > /tmp/moon.json" + docker exec "$CONTAINER_NAME" sh -c "sed -i 's|\"stableEndpoints\": \\[\\]|\"stableEndpoints\": [\"$PUBLIC_IP/9993\"]|' /tmp/moon.json" + docker exec "$CONTAINER_NAME" sh -c "cd /tmp && zerotier-idtool genmoon moon.json" + MOON_FILE=$(docker exec "$CONTAINER_NAME" sh -c "find /tmp -maxdepth 1 -name '*.moon' | head -n1") + [ -n "$MOON_FILE" ] || { echo "Moon 生成失败"; exit 1; } mkdir -p "$MOONS_DIR" - docker cp "zerotier-aio:$MOON_FILE" "$MOONS_DIR/" + docker cp "$CONTAINER_NAME:$MOON_FILE" "$MOONS_DIR/" MOON_ID=$(basename "$MOON_FILE" .moon) - docker restart zerotier-aio + docker restart "$CONTAINER_NAME" >/dev/null else - MOON_ID=$(ls "$MOONS_DIR"/*.moon | head -n1 | xargs basename | cut -d. -f1) + MOON_ID=$(find "$MOONS_DIR" -maxdepth 1 -name '*.moon' | head -n1 | xargs basename | cut -d. -f1) fi # 防火墙(ufw) command -v ufw &>/dev/null && { - ufw allow 9993/udp 3000/tcp 3443/tcp + ufw allow 9993/udp || true + ufw allow 3000/tcp || true + ufw allow 3443/tcp || true ufw reload || true }