Files
deploy-zerotier-aio/deploy-zerotier-aio.sh

172 lines
5.6 KiB
Bash
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
set -Eeuo pipefail
echo "======================================"
echo " ZeroTier AIO 离线快速部署脚本 v2"
echo " 支持备份恢复 / 新服务器迁移"
echo "======================================"
[ "$EUID" -ne 0 ] && { echo "请用 root 执行"; exit 1; }
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 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 -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"
mkdir -p "$INSTALL_DIR"
cd "$INSTALL_DIR"
# 如果有备份包,优先恢复
if ls zerotier-aio-backup*.tar.gz 1>/dev/null 2>&1; then
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
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
# 加载镜像(离线强依赖)
[ -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 <<EOF
services:
zerotier-aio:
image: $IMAGE_REF
pull_policy: never
container_name: $CONTAINER_NAME
restart: unless-stopped
cap_add: [ALL]
devices: [/dev/net/tun]
network_mode: host
volumes:
- ./etc:/opt/key-networks/ztncui/etc
- ./zerotier-one:/var/lib/zerotier-one
- ./zt-mkworld:/etc/zt-mkworld
environment:
- TZ=Asia/Shanghai
- AUTOGEN_PLANET=0
- NODE_ENV=production
- HTTP_PORT=3000
- HTTP_ALL_INTERFACES=yes
- ZTNCUI_PASSWD=admin123
- MYADDR=$PUBLIC_IP
privileged: true
EOF
# 启动
docker compose up -d
echo "等待容器初始化..."
for _ in $(seq 1 30); do
if docker exec "$CONTAINER_NAME" test -f /var/lib/zerotier-one/identity.public >/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 [ "$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 "$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 "$CONTAINER_NAME:$MOON_FILE" "$MOONS_DIR/"
MOON_ID=$(basename "$MOON_FILE" .moon)
docker restart "$CONTAINER_NAME" >/dev/null
else
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 || true
ufw allow 3000/tcp || true
ufw allow 3443/tcp || true
ufw reload || true
}
cat <<EOF
======================================
部署完成!
======================================
Moon ID: $MOON_ID
Orbit 命令: sudo zerotier-cli orbit $MOON_ID $MOON_ID
Web 界面: http://$PUBLIC_IP:3000
用户: admin 密码: admin123 (立即修改!)
安全组需放行: 9993/udp 3000/tcp 3443/tcp
备份建议: tar -czf zerotier-aio-backup-$(date +%Y%m%d).tar.gz /opt/zerotier-aio
调试: docker logs zerotier-aio
docker exec -it zerotier-aio bash
======================================
EOF