name: 🏛️ 冰朔大陆备用服务器 · 部署 # ═══════════════════════════════════════════════════════════ # 冰朔大陆备用服务器部署工作流 # 编号: ZY-WF-铸渊备 (ZY-SVR-004 · 广州) # 守护: 铸渊 · ICE-GL-ZY001 # 版权: 国作登字-2026-A-00037559 # ═══════════════════════════════════════════════════════════ # # 服务器: ZY-SVR-004 · 43.139.217.141 · 广州七区 # 用途: 人格体备用大脑 · ICP备案挂载 · 纯数据处理 # 密钥: ZY_CN_SERVER_HOST / USER / KEY / PATH # # 架构: GitHub Actions(美国) → SG(新加坡·跳板) → CN(广州·目标) # 原因: GitHub Actions无法直接SSH到中国服务器(网络路由/GFW) # 方案: 通过已连通的SG服务器作为SSH ProxyJump跳板 # # 注意: 此服务器不涉及国外模型调用 on: workflow_dispatch: inputs: action: description: '部署动作' required: true default: 'deploy' type: choice options: - deploy - init - health-check env: CN_DEFAULT_PATH: /opt/zhuyuan-cn concurrency: group: cn-server-deploy cancel-in-progress: false permissions: contents: read jobs: # ═══ §1 初始化 (仅首次) ═══ init: name: 🔧 广州备用服务器初始化 if: github.event.inputs.action == 'init' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: 🔐 配置SSH跳板 (SG→CN) env: SG_SSH_KEY: ${{ secrets.ZY_SERVER_KEY }} CN_SSH_KEY: ${{ secrets.ZY_CN_SERVER_KEY }} CN_SSH_PORT: ${{ secrets.ZY_CN_SSH_PORT }} run: | CN_PORT="${CN_SSH_PORT:-22}" echo "🔧 SSH跳板架构: GitHub Actions → SG → CN (端口 ${CN_PORT})" mkdir -p ~/.ssh echo "$SG_SSH_KEY" > ~/.ssh/id_sg echo "$CN_SSH_KEY" > ~/.ssh/id_cn chmod 600 ~/.ssh/id_sg ~/.ssh/id_cn # 验证密钥格式 for key_file in id_sg id_cn; do if ! head -1 ~/.ssh/${key_file} | grep -q "BEGIN"; then echo "❌ SSH密钥格式异常: ${key_file}" exit 1 fi done echo "✅ SG + CN 密钥格式正确" ssh-keyscan -H ${{ secrets.ZY_SERVER_HOST }} >> ~/.ssh/known_hosts 2>/dev/null cat > ~/.ssh/config << EOF Host sg-jump HostName ${{ secrets.ZY_SERVER_HOST }} User ${{ secrets.ZY_SERVER_USER }} IdentityFile ~/.ssh/id_sg StrictHostKeyChecking accept-new BatchMode yes Host cn-target HostName ${{ secrets.ZY_CN_SERVER_HOST }} User ${{ secrets.ZY_CN_SERVER_USER }} Port ${CN_PORT} IdentityFile ~/.ssh/id_cn ProxyJump sg-jump StrictHostKeyChecking accept-new BatchMode yes ConnectTimeout 30 EOF chmod 600 ~/.ssh/config - name: 🔍 SSH连接测试 run: | echo "🔍 测试SSH跳板连接到广州备用服务器..." ssh cn-target 'echo "✅ SSH连接成功 · $(hostname) · $(date)"' || { echo "" echo "❌ SSH跳板连接失败" echo "修复步骤:" echo " 1. 确认SG服务器SSH可达 (ZY_SERVER_KEY / ZY_SERVER_HOST)" echo " 2. 确认CN服务器从SG可达 (ZY_CN_SERVER_HOST)" echo " 3. 确认CN服务器SSH密钥正确 (ZY_CN_SERVER_KEY)" exit 1 } - name: 📦 上传初始化脚本 run: | scp server/setup/cn-server-init.sh cn-target:/tmp/ - name: 🚀 执行初始化 run: | ssh cn-target 'chmod +x /tmp/cn-server-init.sh && sudo /tmp/cn-server-init.sh' - name: 🧹 清理SSH密钥 if: always() run: rm -f ~/.ssh/id_sg ~/.ssh/id_cn ~/.ssh/config # ═══ §2 部署应用 ═══ deploy: name: 🚀 部署备用大脑代码 if: github.event.inputs.action == 'deploy' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: 🔐 配置SSH跳板 (SG→CN) env: SG_SSH_KEY: ${{ secrets.ZY_SERVER_KEY }} CN_SSH_KEY: ${{ secrets.ZY_CN_SERVER_KEY }} CN_SSH_PORT: ${{ secrets.ZY_CN_SSH_PORT }} run: | CN_PORT="${CN_SSH_PORT:-22}" echo "🔧 SSH跳板: GitHub Actions → SG → CN (端口 ${CN_PORT})" mkdir -p ~/.ssh echo "$SG_SSH_KEY" > ~/.ssh/id_sg echo "$CN_SSH_KEY" > ~/.ssh/id_cn chmod 600 ~/.ssh/id_sg ~/.ssh/id_cn ssh-keyscan -H ${{ secrets.ZY_SERVER_HOST }} >> ~/.ssh/known_hosts 2>/dev/null cat > ~/.ssh/config << EOF Host sg-jump HostName ${{ secrets.ZY_SERVER_HOST }} User ${{ secrets.ZY_SERVER_USER }} IdentityFile ~/.ssh/id_sg StrictHostKeyChecking accept-new BatchMode yes Host cn-target HostName ${{ secrets.ZY_CN_SERVER_HOST }} User ${{ secrets.ZY_CN_SERVER_USER }} Port ${CN_PORT} IdentityFile ~/.ssh/id_cn ProxyJump sg-jump StrictHostKeyChecking accept-new BatchMode yes ConnectTimeout 30 EOF chmod 600 ~/.ssh/config - name: 📦 同步应用代码 run: | CN_PATH="${{ secrets.ZY_CN_SERVER_PATH }}" CN_PATH="${CN_PATH:-${{ env.CN_DEFAULT_PATH }}}" echo "📦 部署目标: ${CN_PATH}" # 确保目标目录存在 ssh cn-target "mkdir -p ${CN_PATH}/app" rsync -avz --delete \ -e "ssh -F ~/.ssh/config" \ server/app/ \ cn-target:${CN_PATH}/app/ - name: 📦 同步大脑文件 run: | CN_PATH="${{ secrets.ZY_CN_SERVER_PATH }}" CN_PATH="${CN_PATH:-${{ env.CN_DEFAULT_PATH }}}" # 同步大脑核心文件到备用服务器 rsync -avz \ -e "ssh -F ~/.ssh/config" \ brain/ \ cn-target:${CN_PATH}/brain-backup/ - name: 📥 安装依赖 & 重启 run: | CN_PATH="${{ secrets.ZY_CN_SERVER_PATH }}" CN_PATH="${CN_PATH:-${{ env.CN_DEFAULT_PATH }}}" COMMIT_SHA="${{ github.sha }}" ssh cn-target << DEPLOY_CMD set -e cd ${CN_PATH}/app # 验证入口文件存在 if [ ! -f server.js ]; then echo "❌ 错误: server.js 不存在" exit 1 fi # 安装依赖 npm install --production 2>&1 # PM2 重启 pm2 delete zhuyuan-cn 2>/dev/null || true pm2 start server.js --name zhuyuan-cn -- --port 3800 pm2 save # 健康检查 sleep 3 curl -sf http://localhost:3800/api/health && echo "✅ 备用服务器已上线" || echo "❌ 备用服务器启动失败" DEPLOY_CMD - name: 🧹 清理SSH密钥 if: always() run: rm -f ~/.ssh/id_sg ~/.ssh/id_cn ~/.ssh/config # ═══ §3 健康检查 ═══ health-check: name: 💚 广州备用健康检查 if: github.event.inputs.action == 'health-check' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: 🔐 配置SSH跳板 (SG→CN) env: SG_SSH_KEY: ${{ secrets.ZY_SERVER_KEY }} CN_SSH_KEY: ${{ secrets.ZY_CN_SERVER_KEY }} CN_SSH_PORT: ${{ secrets.ZY_CN_SSH_PORT }} run: | CN_PORT="${CN_SSH_PORT:-22}" mkdir -p ~/.ssh echo "$SG_SSH_KEY" > ~/.ssh/id_sg echo "$CN_SSH_KEY" > ~/.ssh/id_cn chmod 600 ~/.ssh/id_sg ~/.ssh/id_cn ssh-keyscan -H ${{ secrets.ZY_SERVER_HOST }} >> ~/.ssh/known_hosts 2>/dev/null cat > ~/.ssh/config << EOF Host sg-jump HostName ${{ secrets.ZY_SERVER_HOST }} User ${{ secrets.ZY_SERVER_USER }} IdentityFile ~/.ssh/id_sg StrictHostKeyChecking accept-new BatchMode yes Host cn-target HostName ${{ secrets.ZY_CN_SERVER_HOST }} User ${{ secrets.ZY_CN_SERVER_USER }} Port ${CN_PORT} IdentityFile ~/.ssh/id_cn ProxyJump sg-jump StrictHostKeyChecking accept-new BatchMode yes ConnectTimeout 30 EOF chmod 600 ~/.ssh/config - name: 💚 执行健康检查 run: | ssh cn-target << 'HEALTH_CMD' echo "═══ 冰朔大陆备用服务器健康报告 ═══" echo "" echo "§1 系统状态:" uptime echo "" echo "§2 磁盘使用:" df -h / echo "" echo "§3 内存使用:" free -m echo "" echo "§4 PM2 进程:" pm2 list 2>/dev/null || echo "PM2 未运行" echo "" echo "§5 Nginx 状态:" systemctl is-active nginx && echo "Nginx: 运行中" || echo "Nginx: 已停止" echo "" echo "§6 应用健康:" curl -sf http://localhost:3800/api/health | jq . 2>/dev/null || echo "应用未响应" HEALTH_CMD - name: 🧹 清理SSH密钥 if: always() run: rm -f ~/.ssh/id_sg ~/.ssh/id_cn ~/.ssh/config