XuqmGroup-PrivateDeploy/install.sh
徐勤民 a327a262dd feat(deploy): 移除 ops-web、修复 SDK URL 注入、新增一键升级
核心变更:
- 完全移除 ops-web 容器(私有化部署无需运营后台)
- nginx sub_filter 替换前端 JS bundle 中的公网 SDK URL
- deploy.sh 写入正确的 SDK_IM_WS_URL / SDK_IM_API_URL / SDK_FILE_SERVICE_URL
- 新增 scripts/update.sh:热更新脚本,修复配置 + 可选拉镜像 + 重启 + 验证
- 新增 upgrade.sh:一键升级入口,curl 下载后直接执行,流程同 install.sh
- install.sh 检测已有部署(.env 存在),自动路由到 update.sh 而非重跑向导
- 关键配置文件(.env / secrets.env / xuqm.env)在 tarball 解压前备份后恢复

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 18:25:12 +08:00

245 行
10 KiB
Bash
可执行文件

此文件含有模棱两可的 Unicode 字符

此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。

#!/usr/bin/env bash
# XuqmGroup 私有化部署 — 一键安装脚本(已部署环境重新执行将自动升级)
#
# 首次部署:
# curl -fsSL https://xuqinmin.com/xuqmGroup/XuqmGroup-PrivateDeploy/raw/branch/main/install.sh \
# -o install.sh && bash install.sh
#
# 升级已有部署(推荐使用专用升级脚本):
# curl -fsSL https://xuqinmin.com/xuqmGroup/XuqmGroup-PrivateDeploy/raw/branch/main/upgrade.sh \
# -o upgrade.sh && bash upgrade.sh
#
# 或直接执行bash <(curl ...) 形式保留终端交互):
# bash <(curl -fsSL https://xuqinmin.com/xuqmGroup/XuqmGroup-PrivateDeploy/raw/branch/main/install.sh)
#
# 环境变量(可选):
# DEPLOY_HOST 目标机器 IP / 主机名(默认自动检测本机 IP
# INSTALL_DIR 安装目录(默认 /opt/xuqm-private
# XUQM_BRANCH Gitea 分支(默认 main
set -euo pipefail
# ---------------------------------------------------------------------------
# 若 stdin 不是终端curl | bash,强制从 /dev/tty 读取用户输入
# ---------------------------------------------------------------------------
if [ ! -t 0 ]; then
exec bash "$0" "$@" </dev/tty
fi
# ---------------------------------------------------------------------------
# 配置
# ---------------------------------------------------------------------------
GITEA_BASE="https://xuqinmin.com/xuqmGroup/XuqmGroup-PrivateDeploy"
XUQM_BRANCH="${XUQM_BRANCH:-main}"
ARCHIVE_URL="${GITEA_BASE}/archive/${XUQM_BRANCH}.tar.gz"
INSTALL_DIR="${INSTALL_DIR:-/opt/xuqm-private}"
DEPLOY_HOST="${DEPLOY_HOST:-}"
# ---------------------------------------------------------------------------
# 颜色 & 工具函数
# ---------------------------------------------------------------------------
RED='\033[1;31m'; GREEN='\033[1;32m'; YELLOW='\033[1;33m'
CYAN='\033[1;36m'; BOLD='\033[1m'; RESET='\033[0m'
info() { printf "${CYAN}${RESET} %s\n" "$*"; }
ok() { printf "${GREEN}${RESET} %s\n" "$*"; }
warn() { printf "${YELLOW}${RESET} %s\n" "$*"; }
fail() { printf "${RED}\nERROR: %s${RESET}\n" "$*" >&2; exit 1; }
# ---------------------------------------------------------------------------
# Banner
# ---------------------------------------------------------------------------
printf '\n%b══════════════════════════════════════════════════%b\n' "$CYAN" "$RESET"
printf '%b XuqmGroup 私有化部署 — 一键安装向导%b\n' "$BOLD" "$RESET"
printf '%b══════════════════════════════════════════════════%b\n\n' "$CYAN" "$RESET"
# ---------------------------------------------------------------------------
# 检测目标主机 IP
# ---------------------------------------------------------------------------
if [ -z "$DEPLOY_HOST" ]; then
DEPLOY_HOST="$(hostname -I 2>/dev/null | awk '{print $1}' || \
ip route get 1 2>/dev/null | awk '{print $7}' | head -1 || \
echo "127.0.0.1")"
fi
printf ' 安装目录: %b%s%b\n' "$BOLD" "$INSTALL_DIR" "$RESET"
printf ' 目标主机: %b%s%b\n' "$BOLD" "$DEPLOY_HOST" "$RESET"
printf ' 部署分支: %s\n\n' "$XUQM_BRANCH"
# ---------------------------------------------------------------------------
# Step 1 — 检测操作系统
# ---------------------------------------------------------------------------
if command -v apt-get >/dev/null 2>&1; then
PKG_MGR="apt"
apt-get update -qq 2>/dev/null || true
elif command -v yum >/dev/null 2>&1; then
PKG_MGR="yum"
else
fail "不支持的操作系统(需要 apt 或 yum"
fi
ok "包管理器: $PKG_MGR"
pkg_install() {
if [ "$PKG_MGR" = "apt" ]; then
apt-get install -y -qq "$@" 2>/dev/null
else
yum install -y -q "$@" 2>/dev/null
fi
}
# ---------------------------------------------------------------------------
# Step 2 — 安装 Docker
# ---------------------------------------------------------------------------
if ! command -v docker >/dev/null 2>&1; then
info "Docker 未安装,正在安装..."
if [ "$PKG_MGR" = "apt" ]; then
pkg_install ca-certificates curl gnupg lsb-release
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
| gpg --dearmor -o /etc/apt/keyrings/docker.gpg 2>/dev/null
chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" \
> /etc/apt/sources.list.d/docker.list
apt-get update -qq
pkg_install docker-ce docker-ce-cli containerd.io docker-compose-plugin
else
pkg_install yum-utils
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo 2>/dev/null
pkg_install docker-ce docker-ce-cli containerd.io docker-compose-plugin
systemctl enable --now docker 2>/dev/null || true
fi
fi
docker info >/dev/null 2>&1 || { systemctl start docker 2>/dev/null || true; sleep 2; }
docker info >/dev/null 2>&1 || fail "Docker daemon 未运行,请执行: systemctl start docker"
ok "Docker $(docker --version | grep -o '[0-9]*\.[0-9]*\.[0-9]*' | head -1)"
# ---------------------------------------------------------------------------
# Step 3 — 确认 Docker Compose v2
# ---------------------------------------------------------------------------
if ! docker compose version >/dev/null 2>&1; then
info "Docker Compose v2 未安装,正在安装..."
if [ "$PKG_MGR" = "apt" ]; then
pkg_install docker-compose-plugin
else
COMPOSE_VER="v2.27.0"
mkdir -p /usr/local/lib/docker/cli-plugins
curl -fsSL \
"https://github.com/docker/compose/releases/download/${COMPOSE_VER}/docker-compose-$(uname -s)-$(uname -m)" \
-o /usr/local/lib/docker/cli-plugins/docker-compose
chmod +x /usr/local/lib/docker/cli-plugins/docker-compose
fi
fi
ok "Docker Compose $(docker compose version --short 2>/dev/null || echo 'v2')"
# ---------------------------------------------------------------------------
# Step 4 — 安装 python3 + bcrypt新建租户密码哈希
# ---------------------------------------------------------------------------
if ! command -v python3 >/dev/null 2>&1; then
info "python3 未安装,正在安装..."
pkg_install python3
fi
if ! python3 -c "import bcrypt" 2>/dev/null; then
info "python3-bcrypt 未安装,正在安装..."
if [ "$PKG_MGR" = "apt" ]; then
pkg_install python3-bcrypt 2>/dev/null || python3 -m pip install -q bcrypt
else
python3 -m pip install -q bcrypt
fi
fi
python3 -c "import bcrypt" 2>/dev/null || fail "python3-bcrypt 安装失败,请手动执行: pip3 install bcrypt"
ok "python3 + bcrypt"
# ---------------------------------------------------------------------------
# Step 5 — 安装 mysql 客户端(迁移模式需要)
# ---------------------------------------------------------------------------
if ! command -v mysql >/dev/null 2>&1; then
info "mysql 客户端未安装,正在安装(迁移租户模式需要)..."
if [ "$PKG_MGR" = "apt" ]; then
pkg_install mysql-client 2>/dev/null || pkg_install default-mysql-client 2>/dev/null || \
warn "mysql 客户端安装失败,新建租户模式仍可用"
else
pkg_install mysql 2>/dev/null || warn "mysql 客户端安装失败,新建租户模式仍可用"
fi
fi
command -v mysql >/dev/null 2>&1 && ok "mysql 客户端" || warn "mysql 客户端不可用(仅影响迁移模式)"
# ---------------------------------------------------------------------------
# Step 6 — 下载部署包
# ---------------------------------------------------------------------------
printf '\n'
info "下载部署包 ${ARCHIVE_URL} ..."
TMP_PKG="$(mktemp /tmp/xuqm-deploy-XXXXXX.tar.gz)"
_BACKUP_DIR="$(mktemp -d /tmp/xuqm-backup-XXXXXX)"
trap 'rm -f "$TMP_PKG"; rm -rf "$_BACKUP_DIR"' EXIT
curl -fsSL --progress-bar "$ARCHIVE_URL" -o "$TMP_PKG" \
|| fail "部署包下载失败,请检查网络或 Gitea 是否可达: $ARCHIVE_URL"
# ---------------------------------------------------------------------------
# Step 7 — 解压到安装目录(更新时保留关键配置)
# ---------------------------------------------------------------------------
# 检测是否为已有部署
_IS_UPDATE=0
[ -f "$INSTALL_DIR/.env" ] && [ -f "$INSTALL_DIR/config/secrets.env" ] && _IS_UPDATE=1
# 备份关键配置,防止 tarball 中同名文件意外覆盖
if [ "$_IS_UPDATE" -eq 1 ]; then
for _cf in .env config/secrets.env config/xuqm.env; do
[ -f "$INSTALL_DIR/$_cf" ] && \
cp "$INSTALL_DIR/$_cf" "$_BACKUP_DIR/$(basename "$_cf").bak"
done
fi
mkdir -p "$INSTALL_DIR"
tar -xzf "$TMP_PKG" -C "$INSTALL_DIR" --strip-components=1 --exclude='*/data'
chmod +x "$INSTALL_DIR/scripts/"*.sh "$INSTALL_DIR/install.sh" 2>/dev/null || true
ok "部署包解压完成: $INSTALL_DIR"
# 恢复关键配置文件(确保现有配置不被模板覆盖)
if [ "$_IS_UPDATE" -eq 1 ]; then
for _cf in .env config/secrets.env config/xuqm.env; do
_bak="$_BACKUP_DIR/$(basename "$_cf").bak"
[ -f "$_bak" ] && cp "$_bak" "$INSTALL_DIR/$_cf"
done
ok "已恢复现有配置文件"
fi
# ---------------------------------------------------------------------------
# Step 8 — 路由到更新或全量安装
# ---------------------------------------------------------------------------
export DEPLOY_HOST
cd "$INSTALL_DIR"
if [ "$_IS_UPDATE" -eq 1 ]; then
printf '\n'
printf '%b 检测到已有部署(%s/.env 存在)%b\n' "$YELLOW" "$INSTALL_DIR" "$RESET"
printf ' 请选择操作:\n\n'
printf ' %b1%b 仅更新 — 修复配置问题,可选拉取新镜像,重启容器(保留全部数据)\n' "$BOLD" "$RESET"
printf ' %b2%b 全量重部署 — 重新运行完整安装向导(会覆盖现有配置,谨慎使用)\n' "$BOLD" "$RESET"
printf ' %b3%b 退出\n\n' "$BOLD" "$RESET"
read -rp " 请输入 [1/2/3](回车默认 1: " _choice
_choice="${_choice:-1}"
case "$_choice" in
2)
printf '\n%b → 进入全量部署向导 ...%b\n\n' "$GREEN" "$RESET"
exec bash scripts/deploy.sh
;;
3)
printf ' 已退出\n'
exit 0
;;
*)
printf '\n%b → 进入更新流程 ...%b\n\n' "$GREEN" "$RESET"
exec bash scripts/update.sh
;;
esac
else
printf '\n%b 依赖安装完毕,即将进入交互式部署向导 ...%b\n\n' "$GREEN" "$RESET"
exec bash scripts/deploy.sh
fi