# ═══════════════════════════════════════════════ # 🔺 Sovereign: TCS-0002∞ | Root: SYS-GLW-0001 # 📜 Copyright: 国作登字-2026-A-00037559 # ═══════════════════════════════════════════════ # 🌐 铸渊专线V2 · 大脑服务器部署 (多用户独立专线) # # 部署在大脑服务器 ZY-SVR-005 (43.156.237.110) # 独立于面孔服务器的V1 VPN,两套系统并行运行 # # 功能: 每个邮箱绑定独立专线,线路互不干扰 # ═══════════════════════════════════════════════ name: '🌐 铸渊专线V2 · 大脑服务器' on: workflow_dispatch: inputs: action: description: '操作类型' required: true type: choice options: - install - update - status - restart - add-user - remove-user - list-users - send-subscription - send-subscription-v3 - deploy-v3 - switch-v3 - deploy-infinity default: 'status' email: description: '用户邮箱 (add-user/remove-user/send-subscription/send-subscription-v3时需要)' required: false type: string quota_gb: description: '月配额GB (仅add-user时可选,默认500)' required: false type: string default: '500' permissions: contents: read concurrency: group: brain-proxy-deploy cancel-in-progress: false jobs: # ═══ §1 代理服务部署/管理 ═══ deploy-proxy-v2: name: '🌐 V2 · ${{ github.event.inputs.action }}' runs-on: ubuntu-latest if: >- github.event.inputs.action == 'install' || github.event.inputs.action == 'update' || github.event.inputs.action == 'status' || github.event.inputs.action == 'restart' || github.event.inputs.action == 'deploy-v3' || github.event.inputs.action == 'switch-v3' || github.event.inputs.action == 'deploy-infinity' steps: - name: '📥 检出代码' uses: actions/checkout@v4 - name: '🔑 配置SSH密钥' env: SSH_KEY: ${{ secrets.ZY_BRAIN_KEY }} run: | mkdir -p ~/.ssh echo "$SSH_KEY" > ~/.ssh/id_brain chmod 600 ~/.ssh/id_brain if head -1 ~/.ssh/id_brain | grep -q "BEGIN" && tail -1 ~/.ssh/id_brain | grep -q "END"; then echo "✅ SSH私钥格式正确" else echo "❌ SSH私钥格式异常 — 检查 ZY_BRAIN_KEY" exit 1 fi ssh-keyscan -H ${{ secrets.ZY_BRAIN_HOST }} >> ~/.ssh/known_hosts 2>/dev/null - name: '🔍 SSH连接测试' run: | ssh -i ~/.ssh/id_brain -o BatchMode=yes -o ConnectTimeout=10 \ ${{ secrets.ZY_BRAIN_USER }}@${{ secrets.ZY_BRAIN_HOST }} \ 'echo "✅ 大脑服务器连接成功 · $(hostname) · $(date)"' - name: '📦 上传V2代码' run: | ssh -i ~/.ssh/id_brain \ ${{ secrets.ZY_BRAIN_USER }}@${{ secrets.ZY_BRAIN_HOST }} \ "mkdir -p /opt/zhuyuan-brain/proxy-deploy" rsync -avz --delete \ -e "ssh -i ~/.ssh/id_brain" \ server/proxy/ \ ${{ secrets.ZY_BRAIN_USER }}@${{ secrets.ZY_BRAIN_HOST }}:/opt/zhuyuan-brain/proxy-deploy/ - name: '🚀 执行V2部署' env: ZY_BRAIN_HOST: ${{ secrets.ZY_BRAIN_HOST }} ZY_SVR_SV_HOST: ${{ secrets.ZY_SVR_SV_HOST }} ZY_SVR_SV_REALITY_PUBLIC_KEY: ${{ secrets.ZY_SVR_SV_REALITY_PUBLIC_KEY }} ZY_SVR_SV_REALITY_SHORT_ID: ${{ secrets.ZY_SVR_SV_REALITY_SHORT_ID }} ZY_SVR_SV_PORT: ${{ secrets.ZY_SVR_SV_PORT }} ZY_SMTP_USER: ${{ secrets.ZY_SMTP_USER }} ZY_SMTP_PASS: ${{ secrets.ZY_SMTP_PASS }} run: | ACTION="${{ github.event.inputs.action }}" ssh -i ~/.ssh/id_brain \ ${{ secrets.ZY_BRAIN_USER }}@${{ secrets.ZY_BRAIN_HOST }} \ "export ZY_BRAIN_HOST=${ZY_BRAIN_HOST} && \ export ZY_SVR_SV_HOST=${ZY_SVR_SV_HOST:-} && \ export ZY_SVR_SV_REALITY_PUBLIC_KEY=${ZY_SVR_SV_REALITY_PUBLIC_KEY:-} && \ export ZY_SVR_SV_REALITY_SHORT_ID=${ZY_SVR_SV_REALITY_SHORT_ID:-} && \ export ZY_SVR_SV_PORT=${ZY_SVR_SV_PORT:-443} && \ export ZY_SMTP_USER='${ZY_SMTP_USER:-}' && \ export ZY_SMTP_PASS='${ZY_SMTP_PASS:-}' && \ cd /opt/zhuyuan-brain/proxy-deploy && \ bash deploy-brain-proxy.sh ${ACTION}" # ═══ §2 用户管理 ═══ manage-user: name: '👤 用户管理 · ${{ github.event.inputs.action }}' runs-on: ubuntu-latest if: >- github.event.inputs.action == 'add-user' || github.event.inputs.action == 'remove-user' || github.event.inputs.action == 'list-users' steps: - name: '📥 检出代码' uses: actions/checkout@v4 - name: '🔑 配置SSH密钥' env: SSH_KEY: ${{ secrets.ZY_BRAIN_KEY }} run: | mkdir -p ~/.ssh echo "$SSH_KEY" > ~/.ssh/id_brain chmod 600 ~/.ssh/id_brain ssh-keyscan -H ${{ secrets.ZY_BRAIN_HOST }} >> ~/.ssh/known_hosts 2>/dev/null - name: '👤 执行用户操作' run: | ACTION="${{ github.event.inputs.action }}" EMAIL="${{ github.event.inputs.email }}" QUOTA="${{ github.event.inputs.quota_gb }}" case "$ACTION" in add-user) if [ -z "$EMAIL" ]; then echo "❌ 添加用户需要提供邮箱" exit 1 fi echo "➕ 添加用户: $EMAIL (配额: ${QUOTA}GB/月)" ssh -i ~/.ssh/id_brain \ ${{ secrets.ZY_BRAIN_USER }}@${{ secrets.ZY_BRAIN_HOST }} \ "cd /opt/zhuyuan-brain/proxy && \ node service/user-manager.js add '$EMAIL' '${QUOTA}'" echo "" echo "════════════════════════════════════════" echo "✅ 用户已添加!" echo "" echo "下一步: 运行 'send-subscription' 将订阅链接发送到 $EMAIL" echo "════════════════════════════════════════" ;; remove-user) if [ -z "$EMAIL" ]; then echo "❌ 移除用户需要提供邮箱" exit 1 fi echo "➖ 移除用户: $EMAIL" ssh -i ~/.ssh/id_brain \ ${{ secrets.ZY_BRAIN_USER }}@${{ secrets.ZY_BRAIN_HOST }} \ "cd /opt/zhuyuan-brain/proxy && \ node service/user-manager.js remove '$EMAIL'" ;; list-users) echo "📋 用户列表:" ssh -i ~/.ssh/id_brain \ ${{ secrets.ZY_BRAIN_USER }}@${{ secrets.ZY_BRAIN_HOST }} \ "cd /opt/zhuyuan-brain/proxy && \ node service/user-manager.js list" ;; esac # 同步UUID到面孔服务器 (add/remove后自动同步) - name: '🔄 同步UUID到面孔服务器' if: >- (github.event.inputs.action == 'add-user' || github.event.inputs.action == 'remove-user') && success() env: ZY_FACE_KEY: ${{ secrets.ZY_SERVER_KEY }} ZY_FACE_HOST: ${{ secrets.ZY_SERVER_HOST }} ZY_FACE_USER: ${{ secrets.ZY_SERVER_USER }} run: | # 只在面孔服务器密钥可用时同步 if [ -z "$ZY_FACE_KEY" ] || [ -z "$ZY_FACE_HOST" ]; then echo "⚠️ 面孔服务器密钥未配置,跳过UUID同步" echo " 用户仍可使用大脑服务器节点" exit 0 fi echo "$ZY_FACE_KEY" > ~/.ssh/id_face chmod 600 ~/.ssh/id_face ssh-keyscan -H $ZY_FACE_HOST >> ~/.ssh/known_hosts 2>/dev/null echo "🔄 从大脑服务器获取V2用户列表..." V2_USERS=$(ssh -i ~/.ssh/id_brain \ ${{ secrets.ZY_BRAIN_USER }}@${{ secrets.ZY_BRAIN_HOST }} \ "cd /opt/zhuyuan-brain/proxy && \ node -e \" const um = require('./service/user-manager'); const users = um.getEnabledUsers(); const clients = users.map(u => ({id: u.uuid, flow: 'xtls-rprx-vision', email: u.email})); console.log(JSON.stringify(clients)); \"") echo " V2用户数: $(echo "$V2_USERS" | node -e "const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')); console.log(d.length)")" echo "🔄 同步到面孔服务器Xray配置..." ssh -i ~/.ssh/id_face \ ${ZY_FACE_USER}@${ZY_FACE_HOST} \ "XRAY_CONF='/usr/local/etc/xray/config.json' if [ ! -f \"\$XRAY_CONF\" ]; then echo '⚠️ 面孔服务器Xray配置不存在,跳过' exit 0 fi # 保存V2用户列表 echo '${V2_USERS}' > /opt/zhuyuan/proxy/data/v2-clients.json 2>/dev/null || true # 将V2用户追加到Xray配置的clients数组 # 先移除旧的V2用户(email包含@),再添加新的,保留V1原始用户 if command -v jq &>/dev/null; then V2_CLIENTS=\$(cat /opt/zhuyuan/proxy/data/v2-clients.json) jq --argjson v2 \"\$V2_CLIENTS\" ' .inbounds[0].settings.clients = ( [.inbounds[0].settings.clients[] | select(.email == \"bingshuo@zy-proxy\")] + \$v2 ) ' \"\$XRAY_CONF\" > /tmp/xray-config-merged.json if xray run -test -c /tmp/xray-config-merged.json 2>/dev/null; then mv /tmp/xray-config-merged.json \"\$XRAY_CONF\" systemctl restart xray echo '✅ 面孔服务器Xray已同步V2用户并重启' else echo '❌ 合并后配置验证失败,保持原配置' rm -f /tmp/xray-config-merged.json fi else echo '⚠️ jq未安装,请在面孔服务器安装: apt install jq' fi" # ═══ §3 发送订阅 ═══ send-subscription: name: '📧 发送V2订阅' runs-on: ubuntu-latest if: github.event.inputs.action == 'send-subscription' steps: - name: '📥 检出代码' uses: actions/checkout@v4 - name: '🔑 配置SSH密钥' env: SSH_KEY: ${{ secrets.ZY_BRAIN_KEY }} run: | mkdir -p ~/.ssh echo "$SSH_KEY" > ~/.ssh/id_brain chmod 600 ~/.ssh/id_brain ssh-keyscan -H ${{ secrets.ZY_BRAIN_HOST }} >> ~/.ssh/known_hosts 2>/dev/null - name: '📧 获取用户信息并发送' env: ZY_SMTP_USER: ${{ secrets.ZY_SMTP_USER }} ZY_SMTP_PASS: ${{ secrets.ZY_SMTP_PASS }} ZY_BRAIN_HOST: ${{ secrets.ZY_BRAIN_HOST }} run: | EMAIL="${{ github.event.inputs.email }}" if [ -z "$EMAIL" ]; then echo "❌ 发送订阅需要提供邮箱" exit 1 fi echo "📧 获取 $EMAIL 的订阅信息..." # 获取用户token USER_INFO=$(ssh -i ~/.ssh/id_brain \ ${{ secrets.ZY_BRAIN_USER }}@${{ secrets.ZY_BRAIN_HOST }} \ "cd /opt/zhuyuan-brain/proxy && \ node -e \" const um = require('./service/user-manager'); const user = um.loadUsers().users.find(u => u.email === '$EMAIL'); if (user) console.log(JSON.stringify({token: user.token, label: user.label})); else { console.error('用户不存在'); process.exit(1); } \"") if [ -z "$USER_INFO" ]; then echo "❌ 用户 $EMAIL 不存在,请先运行 add-user" exit 1 fi TOKEN=$(echo "$USER_INFO" | node -e "const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')); console.log(d.token)") LABEL=$(echo "$USER_INFO" | node -e "const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')); console.log(d.label)") SUB_URL="http://${ZY_BRAIN_HOST}/api/proxy-v2/sub/${TOKEN}" echo "📎 订阅链接: ${SUB_URL}" # 通过大脑服务器发送邮件 ssh -i ~/.ssh/id_brain \ ${{ secrets.ZY_BRAIN_USER }}@${{ secrets.ZY_BRAIN_HOST }} \ "export ZY_SMTP_USER='${ZY_SMTP_USER}' ZY_SMTP_PASS='${ZY_SMTP_PASS}' && \ cd /opt/zhuyuan-brain/proxy && \ node service/send-subscription.js send '$EMAIL' '$SUB_URL'" || { echo "" echo "⚠️ 邮件发送失败,请手动将以下订阅链接发送给用户:" echo " $SUB_URL" } echo "" echo "✅ 完成!${LABEL} (${EMAIL}) 的独立专线已就绪" # ═══ §4 发送V3订阅 ═══ send-subscription-v3: name: '📧 发送V3订阅' runs-on: ubuntu-latest if: github.event.inputs.action == 'send-subscription-v3' steps: - name: '📥 检出代码' uses: actions/checkout@v4 - name: '🔑 配置SSH密钥' env: SSH_KEY: ${{ secrets.ZY_BRAIN_KEY }} run: | mkdir -p ~/.ssh echo "$SSH_KEY" > ~/.ssh/id_brain chmod 600 ~/.ssh/id_brain ssh-keyscan -H ${{ secrets.ZY_BRAIN_HOST }} >> ~/.ssh/known_hosts 2>/dev/null - name: '📧 获取用户信息并发送V3链接' env: ZY_SMTP_USER: ${{ secrets.ZY_SMTP_USER }} ZY_SMTP_PASS: ${{ secrets.ZY_SMTP_PASS }} ZY_BRAIN_HOST: ${{ secrets.ZY_BRAIN_HOST }} run: | EMAIL="${{ github.event.inputs.email }}" if [ -z "$EMAIL" ]; then echo "❌ 发送V3订阅需要提供邮箱" exit 1 fi echo "📧 获取 $EMAIL 的V3订阅信息..." # 获取用户token USER_INFO=$(ssh -i ~/.ssh/id_brain \ ${{ secrets.ZY_BRAIN_USER }}@${{ secrets.ZY_BRAIN_HOST }} \ "cd /opt/zhuyuan-brain/proxy && \ node -e \" const um = require('./service/user-manager'); const user = um.loadUsers().users.find(u => u.email === '$EMAIL'); if (user) console.log(JSON.stringify({token: user.token, label: user.label})); else { console.error('用户不存在'); process.exit(1); } \"") if [ -z "$USER_INFO" ]; then echo "❌ 用户 $EMAIL 不存在,请先运行 add-user" exit 1 fi TOKEN=$(echo "$USER_INFO" | node -e "const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')); console.log(d.token)") LABEL=$(echo "$USER_INFO" | node -e "const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')); console.log(d.label)") SUB_URL="http://${ZY_BRAIN_HOST}/api/proxy-v3/sub/${TOKEN}" DASHBOARD_URL="http://${ZY_BRAIN_HOST}/api/proxy-v3/dashboard/${TOKEN}" echo "📎 V3订阅链接: ${SUB_URL}" echo "📊 V3仪表盘: ${DASHBOARD_URL}" # 本地发送V3邮件(使用仓库最新代码,避免服务器脚本版本滞后) cd ${{ github.workspace }}/server/proxy node service/send-subscription.js send-v3 "$EMAIL" "$SUB_URL" "$DASHBOARD_URL" || { echo "" echo "⚠️ 邮件发送失败,请手动访问以下链接:" echo " 订阅: $SUB_URL" echo " 仪表盘: $DASHBOARD_URL" } echo "" echo "✅ 完成!${LABEL} (${EMAIL}) 的V3光湖语言世界订阅已发送"