2026-06-23 00:54:00 +00:00
|
|
|
|
#!/usr/bin/env bash
|
|
|
|
|
|
set -euo pipefail
|
|
|
|
|
|
|
|
|
|
|
|
BASE_URL="${GUKO_BASE_URL:-https://mjjtop.com/admin/guko/raw/branch/main}"
|
|
|
|
|
|
INSTALL_DIR="${GUKO_INSTALL_DIR:-/opt/guko}"
|
|
|
|
|
|
COMPOSE_FILE="${INSTALL_DIR}/docker-compose.yml"
|
|
|
|
|
|
ENV_FILE="${INSTALL_DIR}/.env"
|
|
|
|
|
|
SERVERS_FILE="${INSTALL_DIR}/servers.json"
|
2026-06-23 00:58:45 +00:00
|
|
|
|
IMAGE_NAME="${GUKO_IMAGE:-guko:local}"
|
|
|
|
|
|
DEFAULT_TG_ID="${GUKO_TG_ID:-165067365}"
|
|
|
|
|
|
BACKUP_DIR="${GUKO_BACKUP_DIR:-${INSTALL_DIR}/backups}"
|
2026-06-23 00:54:00 +00:00
|
|
|
|
|
|
|
|
|
|
need_root() {
|
|
|
|
|
|
if [ "$(id -u)" -ne 0 ]; then
|
|
|
|
|
|
echo "请用 root 运行:sudo bash <(curl -fsSL https://mjjtop.com/guko)" >&2
|
|
|
|
|
|
exit 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
install_docker() {
|
|
|
|
|
|
if command -v docker >/dev/null 2>&1 && docker compose version >/dev/null 2>&1; then
|
|
|
|
|
|
return
|
|
|
|
|
|
fi
|
|
|
|
|
|
echo "==> 安装 Docker / Compose"
|
|
|
|
|
|
curl -fsSL https://get.docker.com | sh
|
|
|
|
|
|
systemctl enable --now docker >/dev/null 2>&1 || true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-23 00:58:45 +00:00
|
|
|
|
render_compose() {
|
|
|
|
|
|
cat > "${COMPOSE_FILE}" <<COMPOSE
|
|
|
|
|
|
name: guko
|
|
|
|
|
|
services:
|
|
|
|
|
|
guko-bot:
|
|
|
|
|
|
image: ${IMAGE_NAME}
|
|
|
|
|
|
build:
|
|
|
|
|
|
context: .
|
|
|
|
|
|
dockerfile: telegram-bot/Dockerfile
|
|
|
|
|
|
container_name: guko-bot
|
|
|
|
|
|
restart: unless-stopped
|
|
|
|
|
|
env_file: .env
|
|
|
|
|
|
volumes:
|
|
|
|
|
|
- ./servers.json:/data/servers.json
|
|
|
|
|
|
- ./keys:/data/keys
|
|
|
|
|
|
- ./media:/data/media
|
|
|
|
|
|
- ./results:/data/results
|
|
|
|
|
|
- ./history.json:/data/history.json
|
|
|
|
|
|
- ./tmp:/data/tmp
|
|
|
|
|
|
COMPOSE
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fetch_source() {
|
|
|
|
|
|
echo "==> 下载 GUKO 源码"
|
|
|
|
|
|
local tmp
|
|
|
|
|
|
tmp="$(mktemp -d)"
|
|
|
|
|
|
fetch "${BASE_URL}/telegram-bot/Dockerfile" "${tmp}/Dockerfile.check"
|
|
|
|
|
|
rm -rf "${INSTALL_DIR}/telegram-bot" "${INSTALL_DIR}/optional" "${INSTALL_DIR}/scripts" \
|
|
|
|
|
|
"${INSTALL_DIR}/auth.py" "${INSTALL_DIR}/guko.py" "${INSTALL_DIR}/jiaoops.py" \
|
|
|
|
|
|
"${INSTALL_DIR}/Makefile" "${INSTALL_DIR}/README.md" "${INSTALL_DIR}/LICENSE"
|
|
|
|
|
|
fetch "https://mjjtop.com/admin/guko/archive/main.tar.gz" "${tmp}/guko.tar.gz"
|
|
|
|
|
|
tar -xzf "${tmp}/guko.tar.gz" -C "${tmp}"
|
|
|
|
|
|
local src
|
|
|
|
|
|
src="$(find "${tmp}" -maxdepth 1 -type d \( -name 'guko' -o -name 'guko-*' \) | head -1)"
|
|
|
|
|
|
if [ -z "${src}" ] || [ ! -d "${src}" ]; then
|
|
|
|
|
|
src="$(find "${tmp}" -maxdepth 1 -mindepth 1 -type d | head -1)"
|
|
|
|
|
|
fi
|
|
|
|
|
|
cp -a "${src}/auth.py" "${src}/guko.py" "${src}/jiaoops.py" "${src}/telegram-bot" "${INSTALL_DIR}/"
|
|
|
|
|
|
[ -d "${src}/optional" ] && cp -a "${src}/optional" "${INSTALL_DIR}/" || true
|
|
|
|
|
|
[ -d "${src}/scripts" ] && cp -a "${src}/scripts" "${INSTALL_DIR}/" || true
|
|
|
|
|
|
cp -a "${src}/README.md" "${src}/LICENSE" "${INSTALL_DIR}/" 2>/dev/null || true
|
|
|
|
|
|
rm -rf "${tmp}"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-23 00:54:00 +00:00
|
|
|
|
fetch() {
|
|
|
|
|
|
local url="$1" out="$2"
|
|
|
|
|
|
curl -fL --retry 3 --connect-timeout 10 "$url" -o "$out"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
init_files() {
|
|
|
|
|
|
echo "==> 初始化 ${INSTALL_DIR}"
|
|
|
|
|
|
mkdir -p "${INSTALL_DIR}" "${INSTALL_DIR}/keys" "${INSTALL_DIR}/media" "${INSTALL_DIR}/results" "${INSTALL_DIR}/tmp"
|
|
|
|
|
|
chmod 700 "${INSTALL_DIR}/keys"
|
|
|
|
|
|
|
2026-06-23 00:58:45 +00:00
|
|
|
|
fetch_source
|
|
|
|
|
|
render_compose
|
2026-06-23 00:54:00 +00:00
|
|
|
|
|
|
|
|
|
|
if [ ! -f "${ENV_FILE}" ]; then
|
|
|
|
|
|
fetch "${BASE_URL}/.env.example" "${ENV_FILE}"
|
|
|
|
|
|
sed -i \
|
|
|
|
|
|
-e 's/^BOT_TOKEN=.*/BOT_TOKEN=replace-me/' \
|
2026-06-23 00:58:45 +00:00
|
|
|
|
-e "s/^ALLOWED_USERS=.*/ALLOWED_USERS=${DEFAULT_TG_ID}/" \
|
|
|
|
|
|
-e "s/^ADMIN_USERS=.*/ADMIN_USERS=${DEFAULT_TG_ID}/" \
|
2026-06-23 00:54:00 +00:00
|
|
|
|
"${ENV_FILE}"
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
if [ ! -f "${SERVERS_FILE}" ]; then
|
|
|
|
|
|
fetch "${BASE_URL}/servers.example.json" "${SERVERS_FILE}"
|
|
|
|
|
|
fi
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
usage() {
|
|
|
|
|
|
cat <<USAGE
|
|
|
|
|
|
GUKO 一键部署脚本
|
|
|
|
|
|
|
|
|
|
|
|
用法:
|
|
|
|
|
|
bash <(curl -fsSL https://mjjtop.com/guko) install 安装/初始化
|
|
|
|
|
|
bash <(curl -fsSL https://mjjtop.com/guko) up 启动
|
|
|
|
|
|
bash <(curl -fsSL https://mjjtop.com/guko) down 停止
|
|
|
|
|
|
bash <(curl -fsSL https://mjjtop.com/guko) restart 重启
|
|
|
|
|
|
bash <(curl -fsSL https://mjjtop.com/guko) logs 看日志
|
|
|
|
|
|
bash <(curl -fsSL https://mjjtop.com/guko) status 状态
|
2026-06-23 00:58:45 +00:00
|
|
|
|
bash <(curl -fsSL https://mjjtop.com/guko) update 更新源码/重建镜像并重启
|
|
|
|
|
|
bash <(curl -fsSL https://mjjtop.com/guko) pull 只更新源码和 compose
|
|
|
|
|
|
bash <(curl -fsSL https://mjjtop.com/guko) backup 备份配置/密钥/历史
|
|
|
|
|
|
bash <(curl -fsSL https://mjjtop.com/guko) doctor 检查部署状态
|
|
|
|
|
|
bash <(curl -fsSL https://mjjtop.com/guko) repo 打印仓库地址
|
2026-06-23 00:54:00 +00:00
|
|
|
|
|
|
|
|
|
|
安装目录:${INSTALL_DIR}
|
|
|
|
|
|
首次安装后必须编辑:${ENV_FILE}
|
|
|
|
|
|
BOT_TOKEN=你的 Telegram Bot Token
|
|
|
|
|
|
ALLOWED_USERS=你的 Telegram 数字 ID
|
|
|
|
|
|
ADMIN_USERS=你的 Telegram 数字 ID
|
|
|
|
|
|
USAGE
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
compose() {
|
|
|
|
|
|
cd "${INSTALL_DIR}"
|
|
|
|
|
|
docker compose -f "${COMPOSE_FILE}" "$@"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-23 00:58:45 +00:00
|
|
|
|
backup_data() {
|
|
|
|
|
|
mkdir -p "${BACKUP_DIR}"
|
|
|
|
|
|
chmod 700 "${BACKUP_DIR}"
|
|
|
|
|
|
local out
|
|
|
|
|
|
out="${BACKUP_DIR}/guko-backup-$(date +%Y%m%d-%H%M%S).tar.gz"
|
|
|
|
|
|
tar -C "${INSTALL_DIR}" -czf "${out}" \
|
|
|
|
|
|
.env servers.json history.json keys media results tmp 2>/dev/null || true
|
|
|
|
|
|
chmod 600 "${out}"
|
|
|
|
|
|
echo "✅ 备份完成:${out}"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
doctor() {
|
|
|
|
|
|
echo "== GUKO doctor =="
|
|
|
|
|
|
echo "install_dir=${INSTALL_DIR}"
|
|
|
|
|
|
echo "compose=${COMPOSE_FILE}"
|
|
|
|
|
|
command -v docker >/dev/null 2>&1 && docker --version || echo "docker=missing"
|
|
|
|
|
|
docker compose version 2>/dev/null || echo "docker compose=missing"
|
|
|
|
|
|
[ -f "${ENV_FILE}" ] && echo ".env=ok" || echo ".env=missing"
|
|
|
|
|
|
[ -f "${SERVERS_FILE}" ] && echo "servers.json=ok" || echo "servers.json=missing"
|
|
|
|
|
|
if [ -f "${ENV_FILE}" ]; then
|
|
|
|
|
|
grep -E '^(BOT_TOKEN|ALLOWED_USERS|ADMIN_USERS)=' "${ENV_FILE}" | sed -E 's/(BOT_TOKEN=).*/\1***/'
|
|
|
|
|
|
fi
|
|
|
|
|
|
if [ -f "${COMPOSE_FILE}" ] && command -v docker >/dev/null 2>&1; then
|
|
|
|
|
|
compose ps || true
|
|
|
|
|
|
fi
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-23 00:54:00 +00:00
|
|
|
|
cmd="${1:-install}"
|
|
|
|
|
|
case "$cmd" in
|
|
|
|
|
|
install|init)
|
|
|
|
|
|
need_root
|
|
|
|
|
|
install_docker
|
|
|
|
|
|
init_files
|
|
|
|
|
|
cat <<MSG
|
|
|
|
|
|
|
|
|
|
|
|
✅ GUKO 已初始化到:${INSTALL_DIR}
|
|
|
|
|
|
|
|
|
|
|
|
下一步:
|
|
|
|
|
|
1. 编辑配置:nano ${ENV_FILE}
|
|
|
|
|
|
2. 填好 BOT_TOKEN / ALLOWED_USERS / ADMIN_USERS
|
|
|
|
|
|
3. 启动:bash <(curl -fsSL https://mjjtop.com/guko) up
|
|
|
|
|
|
4. Telegram 私聊 Bot 发送 /start,再用 /addserver 添加服务器
|
|
|
|
|
|
|
|
|
|
|
|
MSG
|
|
|
|
|
|
;;
|
|
|
|
|
|
up|start)
|
|
|
|
|
|
need_root
|
|
|
|
|
|
[ -f "${COMPOSE_FILE}" ] || { echo "未安装,先执行 install" >&2; exit 1; }
|
2026-06-23 00:58:45 +00:00
|
|
|
|
compose build --pull
|
2026-06-23 00:54:00 +00:00
|
|
|
|
compose up -d
|
|
|
|
|
|
compose ps
|
|
|
|
|
|
;;
|
|
|
|
|
|
down|stop)
|
|
|
|
|
|
need_root
|
|
|
|
|
|
compose down
|
|
|
|
|
|
;;
|
|
|
|
|
|
restart)
|
|
|
|
|
|
need_root
|
|
|
|
|
|
compose restart
|
|
|
|
|
|
compose ps
|
|
|
|
|
|
;;
|
|
|
|
|
|
update)
|
|
|
|
|
|
need_root
|
2026-06-23 00:58:45 +00:00
|
|
|
|
install_docker
|
|
|
|
|
|
init_files
|
|
|
|
|
|
compose build --pull
|
2026-06-23 00:54:00 +00:00
|
|
|
|
compose up -d
|
|
|
|
|
|
compose ps
|
|
|
|
|
|
;;
|
2026-06-23 00:58:45 +00:00
|
|
|
|
pull)
|
|
|
|
|
|
need_root
|
|
|
|
|
|
init_files
|
|
|
|
|
|
;;
|
|
|
|
|
|
backup)
|
|
|
|
|
|
need_root
|
|
|
|
|
|
backup_data
|
|
|
|
|
|
;;
|
|
|
|
|
|
doctor)
|
|
|
|
|
|
need_root
|
|
|
|
|
|
doctor
|
|
|
|
|
|
;;
|
|
|
|
|
|
repo)
|
|
|
|
|
|
echo "https://mjjtop.com/guko-repo"
|
|
|
|
|
|
;;
|
2026-06-23 00:54:00 +00:00
|
|
|
|
logs)
|
|
|
|
|
|
need_root
|
|
|
|
|
|
compose logs -f --tail=200
|
|
|
|
|
|
;;
|
|
|
|
|
|
status|ps)
|
|
|
|
|
|
need_root
|
|
|
|
|
|
compose ps
|
|
|
|
|
|
;;
|
|
|
|
|
|
help|-h|--help)
|
|
|
|
|
|
usage
|
|
|
|
|
|
;;
|
|
|
|
|
|
*)
|
|
|
|
|
|
usage
|
|
|
|
|
|
exit 2
|
|
|
|
|
|
;;
|
|
|
|
|
|
esac
|