#!/bin/bash # EasyAI 一键部署脚本 # 支持交互式问答配置,兼容 IP 与域名两种访问方式 # 一行命令: git clone https://git.51easyai.com/wangbo/easyai && cd easyai && chmod +x ./start.sh && ./start.sh set -e # 仅配置模式(验证用):DEPLOY_DRY_RUN=1 只生成配置文件,不执行 Docker 安装和启动 DEPLOY_DRY_RUN="${DEPLOY_DRY_RUN:-0}" # ==================== 项目初始化 ==================== init_project_dir() { local script_source script_source="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)" if [ -f "${script_source}/docker-compose.yml" ]; then echo "📁 项目目录: ${script_source}" cd "$script_source" return 0 fi echo "❌ 未找到 docker-compose.yml,请在 easyai 项目目录下运行 start.sh" echo " 启动命令: git clone https://git.51easyai.com/wangbo/easyai && cd easyai && chmod +x ./start.sh && ./start.sh" exit 1 } # ==================== 配置变量(支持环境变量非交互模式) ==================== DEPLOY_MODE="" # ip | domain DEPLOY_IP="" DEPLOY_DOMAIN="" DEPLOY_HTTPS=false prompt_or_env() { local var_name=$1 local prompt_text=$2 local env_name=$3 local default=$4 if [ -n "${!env_name}" ]; then eval "$var_name=\"${!env_name}\"" return fi if [ -n "$default" ]; then read -r -p "${prompt_text} [$default]: " input eval "$var_name=\"${input:-$default}\"" else read -r -p "${prompt_text}: " input eval "$var_name=\"$input\"" fi } run_deploy_questions() { echo "" echo "================================" echo " EasyAI 部署配置(问答模式)" echo "================================" echo "" # 非交互模式:环境变量已完整设置则直接使用(CI/自动化部署) if [ -n "$DEPLOY_ACCESS" ]; then if [ "$DEPLOY_ACCESS" = "ip" ] && [ -n "$DEPLOY_IP" ]; then DEPLOY_MODE="ip" echo "使用环境变量: IP 模式, IP=$DEPLOY_IP" return fi if [ "$DEPLOY_ACCESS" = "domain" ] && [ -n "$DEPLOY_DOMAIN" ]; then DEPLOY_MODE="domain" DEPLOY_HTTPS="${DEPLOY_HTTPS_INPUT:-false}" echo "使用环境变量: 域名模式, 域名=$DEPLOY_DOMAIN" return fi fi # 1. IP 或域名访问 if [ -z "$DEPLOY_ACCESS" ]; then echo "1. 通过 IP 地址还是域名访问?" echo " [1] IP 地址(需开放 3001、3002、3003 端口)" echo " [2] 域名" read -r -p "请选择 [1/2]: " choice case "$choice" in 1) DEPLOY_MODE="ip" ;; 2) DEPLOY_MODE="domain" ;; *) echo "❌ 无效选择"; exit 1 ;; esac else DEPLOY_MODE="$DEPLOY_ACCESS" fi if [ "$DEPLOY_MODE" = "ip" ]; then # 2. 输入服务器 IP prompt_or_env DEPLOY_IP "2. 请输入服务器 IP 地址" "DEPLOY_IP" "" [ -z "$DEPLOY_IP" ] && { echo "❌ IP 不能为空"; exit 1; } echo " 请确保防火墙已放行 3001、3002、3003 端口" else # 3. 输入域名 prompt_or_env DEPLOY_DOMAIN "3. 请输入域名(不含 https:// 前缀,如 51easyai.com)" "DEPLOY_DOMAIN" "" [ -z "$DEPLOY_DOMAIN" ] && { echo "❌ 域名不能为空"; exit 1; } # 3.1 是否启用 HTTPS if [ -n "$DEPLOY_HTTPS_INPUT" ]; then DEPLOY_HTTPS=$DEPLOY_HTTPS_INPUT else read -r -p "3.1 是否启用 HTTPS?[y/N]: " https_choice DEPLOY_HTTPS=false [[ "$https_choice" =~ ^[yY] ]] && DEPLOY_HTTPS=true fi [ "$DEPLOY_HTTPS" = true ] && echo " 启用 HTTPS 需确保防火墙已放行 80、443 端口" fi } # ==================== 生成配置文件 ==================== setup_env_files() { echo "" echo "📝 配置环境文件..." # 6. 复制 .env.tools 和 .env.ASG [ ! -f .env.tools ] && cp .env.tools.sample .env.tools && echo " ✓ .env.tools" [ ! -f .env.ASG ] && cp .env.ASG.sample .env.ASG && echo " ✓ .env.ASG" # 4/5. 配置 .env if [ ! -f .env ]; then cp .env.sample .env fi if [ "$DEPLOY_MODE" = "ip" ]; then # IP 模式 sed -i.bak "s|^NUXT_PUBLIC_BASE_APIURL=.*|NUXT_PUBLIC_BASE_APIURL=http://${DEPLOY_IP}:3001|" .env sed -i.bak "s|^NUXT_PUBLIC_BASE_SOCKETURL=.*|NUXT_PUBLIC_BASE_SOCKETURL=ws://${DEPLOY_IP}:3002|" .env sed -i.bak "s|^NUXT_PUBLIC_SG_APIURL=.*|NUXT_PUBLIC_SG_APIURL=http://${DEPLOY_IP}:3003|" .env echo " ✓ .env 已配置为 IP 模式 (${DEPLOY_IP})" else # 域名模式 sed -i.bak "s|^NUXT_PUBLIC_BASE_APIURL=.*|NUXT_PUBLIC_BASE_APIURL=/api|" .env sed -i.bak "s|^NUXT_PUBLIC_BASE_SOCKETURL=.*|NUXT_PUBLIC_BASE_SOCKETURL=wss://${DEPLOY_DOMAIN}/socket.io|" .env sed -i.bak "s|^NUXT_PUBLIC_SG_APIURL=.*|NUXT_PUBLIC_SG_APIURL=/asg-api|" .env echo " ✓ .env 已配置为域名模式 (${DEPLOY_DOMAIN})" # 7. Nginx 配置(域名模式) PROXY_CONF="${DEPLOY_DOMAIN}.conf" if [ ! -f "$PROXY_CONF" ]; then sed "s/51easyai.com/${DEPLOY_DOMAIN}/g" easyai-proxy.conf.sample > "$PROXY_CONF" echo " ✓ Nginx 配置已生成: $PROXY_CONF" fi fi rm -f .env.bak } # ==================== Docker 安装(复用原 start.sh 逻辑) ==================== install_docker() { echo "" echo "================================" echo " Docker 安装与检查" echo "================================" if [ -f /etc/os-release ]; then . /etc/os-release case "${ID:-}" in ubuntu|debian) OS_FAMILY="Ubuntu" ;; centos|rhel|fedora) OS_FAMILY="CentOS" ;; *) OS_FAMILY="${ID:-Unknown}" ;; esac else OS_FAMILY=$(hostnamectl 2>/dev/null | grep "Operating System" | awk '{print $3}' || echo "Unknown") fi OS_VERSION_ID=$(grep -oP '(?<=^VERSION_ID=")[0-9.]+' /etc/os-release 2>/dev/null | cut -d'.' -f1 || echo "0") OS_CODENAME="" [[ "$OS_FAMILY" == "Ubuntu" ]] && OS_CODENAME=$(lsb_release -cs 2>/dev/null || (grep VERSION_CODENAME /etc/os-release 2>/dev/null | cut -d= -f2 | tr -d '"')) UBUNTU_DOCKER_MIRROR_URL="https://mirrors.ustc.edu.cn/docker-ce" UBUNTU_DOCKER_GPG_URL="https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/gpg" CENTOS_DOCKER_MIRROR_URL="https://mirrors.tuna.tsinghua.edu.cn/docker-ce" check_network() { if curl -sSf --connect-timeout 5 https://download.docker.com/ &>/dev/null; then echo "✅ 网络连接正常" return 0 fi echo "⚠️ 将使用国内镜像源" return 0 } check_network if command -v docker &>/dev/null; then echo "✅ Docker 已安装" else if [[ "$OS_FAMILY" == "Ubuntu" ]]; then sudo apt update -y sudo apt install -y apt-transport-https ca-certificates curl gnupg lsb-release sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL "$UBUNTU_DOCKER_GPG_URL" | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg 2>/dev/null || \ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg sudo chmod a+r /etc/apt/keyrings/docker.gpg echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] $UBUNTU_DOCKER_MIRROR_URL/linux/ubuntu $OS_CODENAME stable" | sudo tee /etc/apt/sources.list.d/docker.list >/dev/null sudo apt-get update -y sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin elif [[ "$OS_FAMILY" == "CentOS" ]]; then sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo sed -i "s+https://download.docker.com+$CENTOS_DOCKER_MIRROR_URL+g" /etc/yum.repos.d/docker-ce.repo [[ "$OS_VERSION_ID" -ge "8" ]] && sudo yum module disable -y container-tools 2>/dev/null || true sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin else echo "❌ 不支持的操作系统: $OS_FAMILY" exit 1 fi sudo systemctl enable docker sudo systemctl start docker getent group docker | grep -qw "$USER" || sudo usermod -aG docker "$USER" fi if docker compose version &>/dev/null; then echo "✅ Docker Compose 已就绪" elif command -v docker-compose &>/dev/null; then echo "✅ Docker Compose (兼容模式) 已就绪" else echo "❌ 请安装 docker-compose-plugin" exit 1 fi } # ==================== 启动服务 ==================== start_services() { echo "" echo "🚀 启动 EasyAI 服务..." if docker compose version &>/dev/null; then sudo docker compose pull && sudo docker compose up -d else sudo docker-compose pull && sudo docker-compose up -d fi echo "🎉 EasyAI 应用启动成功" } # ==================== 执行 HTTPS 配置 ==================== run_https_setup() { if [ "$DEPLOY_HTTPS" = true ] && [ -n "$DEPLOY_DOMAIN" ]; then echo "" echo "🔒 执行 HTTPS 配置(请确保服务器已放行 80、443 端口)..." if [ -f "./https.sh" ]; then # https.sh 依赖 easyai-proxy.conf,需使用生成的域名配置文件 export EASYAI_PROXY_CONF="${DEPLOY_DOMAIN}.conf" bash ./https.sh else echo "⚠️ 未找到 https.sh,请手动配置 HTTPS" fi fi } # ==================== 主流程 ==================== main() { init_project_dir # 检查是否已有 .env 且非强制重新配置 if [ -f .env ] && [ -z "$DEPLOY_FORCE_RECONFIG" ] && [ -z "$DEPLOY_ACCESS" ]; then echo "📁 检测到已有 .env 配置" read -r -p "是否重新配置部署方式?[y/N]: " reconfigure if [[ ! "$reconfigure" =~ ^[yY] ]]; then echo "⏭️ 使用现有配置继续..." DEPLOY_MODE="skip" fi fi if [ "$DEPLOY_MODE" != "skip" ]; then run_deploy_questions fi if [ "$DEPLOY_MODE" != "skip" ]; then setup_env_files else [ ! -f .env.tools ] && cp .env.tools.sample .env.tools [ ! -f .env.ASG ] && cp .env.ASG.sample .env.ASG fi if [ "$DEPLOY_DRY_RUN" = "1" ]; then echo "" echo "⚠️ dry-run 模式:跳过 Docker 安装和服务启动" echo " 配置文件已生成,可直接运行 ./start.sh 完成部署" else install_docker start_services run_https_setup fi echo "" echo "================================" echo " 部署完成" echo "================================" if [ "$DEPLOY_MODE" = "ip" ] && [ -n "$DEPLOY_IP" ]; then echo "访问地址: http://${DEPLOY_IP}:3010" elif [ "$DEPLOY_MODE" = "domain" ] && [ -n "$DEPLOY_DOMAIN" ]; then echo "访问地址: http://${DEPLOY_DOMAIN} (配置 Nginx 后)" [ "$DEPLOY_HTTPS" = true ] && echo "HTTPS 已启用" fi echo "" } main "$@"