#!/usr/bin/env bash # # College AI Center — 一键部署脚本 # # 用法: # ./deploy.sh # # 作用:把本地代码同步到远程服务器,在服务器上安装依赖、构建前后端、 # 配置 PostgreSQL 数据库、systemd 服务与 nginx(域名 mc.all8ai.top),并启动。 # # 与服务器上已有的 k12 应用互不影响(使用独立端口 3100/4100、独立目录、 # 名称匹配的 nginx server_name,不占用 default_server)。 # # 依赖(本机):sshpass、rsync、ssh # --------------------------------------------------------------------------- set -euo pipefail # ====== 可配置参数 ====== SERVER_IP="${SERVER_IP:-101.96.196.218}" SERVER_USER="${SERVER_USER:-root}" SERVER_PASS="${SERVER_PASS:-Why_701208}" REMOTE_DIR="/opt/college-ai-center" BACKEND_PORT=3100 FRONTEND_PORT=4100 # 数据库 DB_NAME="college_ai_center" DB_USER="cac_user" DB_PASS="${DB_PASS:-Cac_$(echo "$SERVER_PASS" | md5sum 2>/dev/null | cut -c1-12 || echo Pg88dev)}" # 大模型配置(如需启用,部署后在服务器 .env 中填写 LLM_API_KEY) LLM_API_KEY="${LLM_API_KEY:-}" LLM_BASE_URL="${LLM_BASE_URL:-https://dashscope.aliyuncs.com/compatible-mode/v1}" LLM_MODEL="${LLM_MODEL:-qwen-plus}" JWT_SECRET="${JWT_SECRET:-cac-prod-$(openssl rand -hex 16 2>/dev/null || echo change-me-in-prod)}" SSH_OPTS="-o StrictHostKeyChecking=no -o ConnectTimeout=20" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" ssh_run() { sshpass -p "$SERVER_PASS" ssh $SSH_OPTS "$SERVER_USER@$SERVER_IP" "$@"; } echo "==> [1/6] 检查本机依赖" for c in sshpass rsync ssh; do command -v "$c" >/dev/null 2>&1 || { echo "缺少命令:$c,请先安装(mac: brew install $c)"; exit 1; } done echo "==> [2/6] 同步代码到 $SERVER_IP:$REMOTE_DIR" ssh_run "mkdir -p $REMOTE_DIR" sshpass -p "$SERVER_PASS" rsync -az --delete -e "ssh $SSH_OPTS" \ --exclude 'node_modules' \ --exclude 'web/node_modules' \ --exclude '.next' \ --exclude 'web/.next' \ --exclude 'dist' \ --exclude '.git' \ --exclude 'coverage' \ --exclude '*.log' \ "$SCRIPT_DIR/" "$SERVER_USER@$SERVER_IP:$REMOTE_DIR/" echo "==> [3/6] 在服务器上准备数据库" ssh_run "sudo -u postgres psql -tc \"SELECT 1 FROM pg_roles WHERE rolname='$DB_USER'\" | grep -q 1 || sudo -u postgres psql -c \"CREATE ROLE $DB_USER LOGIN PASSWORD '$DB_PASS';\"" ssh_run "sudo -u postgres psql -tc \"SELECT 1 FROM pg_database WHERE datname='$DB_NAME'\" | grep -q 1 || sudo -u postgres psql -c \"CREATE DATABASE $DB_NAME OWNER $DB_USER;\"" ssh_run "sudo -u postgres psql -c \"ALTER DATABASE $DB_NAME OWNER TO $DB_USER;\" >/dev/null 2>&1 || true" echo "==> [4/6] 写入后端 .env" ssh_run "cat > $REMOTE_DIR/.env < [5/6] 安装依赖并构建(后端 + 前端)" ssh_run "set -e; cd $REMOTE_DIR && npm install --no-audit --no-fund && npm run build" ssh_run "set -e; cd $REMOTE_DIR/web && npm install --no-audit --no-fund && BACKEND_URL=http://127.0.0.1:$BACKEND_PORT npm run build" echo "==> [6/6] 配置 systemd 服务" # 后端 systemd ssh_run "cat > /etc/systemd/system/cac-backend.service < /etc/systemd/system/cac-frontend.service </dev/null 2>&1 || true" # 若 ufw 启用,则放行端口 ssh_run "if ufw status 2>/dev/null | grep -q 'Status: active'; then ufw allow $BACKEND_PORT/tcp; ufw allow $FRONTEND_PORT/tcp; fi || true" echo "==> 启动服务" ssh_run "systemctl daemon-reload && systemctl enable cac-backend cac-frontend >/dev/null 2>&1 && systemctl restart cac-backend cac-frontend" echo "==> 等待服务就绪" sleep 6 ssh_run "systemctl is-active cac-backend cac-frontend; echo '--- backend health ---'; curl -s -o /dev/null -w 'backend(api/auth/login probe): %{http_code}\n' -X POST http://127.0.0.1:$BACKEND_PORT/api/auth/login -H 'Content-Type: application/json' -d '{}'; echo '--- frontend ---'; curl -s -o /dev/null -w 'frontend: %{http_code}\n' http://127.0.0.1:$FRONTEND_PORT" echo "" echo "============================================================" echo " 部署完成!" echo " 前端访问: http://${SERVER_IP}:$FRONTEND_PORT" echo " 后端 API: http://${SERVER_IP}:$BACKEND_PORT/api" echo " 数据库 : $DB_NAME (用户 $DB_USER)" echo "" echo " 测试账户:student / mentor / admin(密码同 *123,如 student123)" echo "" echo " 常用运维:" echo " systemctl status cac-backend cac-frontend" echo " journalctl -u cac-backend -f" echo " journalctl -u cac-frontend -f" echo "============================================================"