From 6de783ad4faea67e8c747b7d3e7788bc4dc500c7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 12 Apr 2026 00:21:22 +0000 Subject: [PATCH] =?UTF-8?q?fix:=20guanghulab.com=E6=97=A0=E6=B3=95?= =?UTF-8?q?=E6=89=93=E5=BC=80=20+=20guanghulab.online=20API=E4=B8=8D?= =?UTF-8?q?=E9=80=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根因修复: 1. cn-domain.conf: server_name支持裸域名+www双变体 2. deploy-cn-landing.yml: 域名双变体处理 + setup-ssl动作(certbot) + SSL自动注入 3. deploy-to-zhuyuan-server.yml: push事件部署前端到production(guanghulab.online=主域名=production) 4. zhuyuan-sovereign.conf: /api/chat添加CORS头+X-Forwarded-Proto Agent-Logs-Url: https://github.com/qinfendebingshuo/guanghulab/sessions/80e337de-dabe-4e86-a711-62d4c47762ec Co-authored-by: qinfendebingshuo <207279273+qinfendebingshuo@users.noreply.github.com> --- .github/workflows/deploy-cn-landing.yml | 160 ++++++++++++++++-- .../workflows/deploy-to-zhuyuan-server.yml | 19 ++- server/nginx/cn-domain.conf | 11 +- server/nginx/zhuyuan-sovereign.conf | 16 ++ 4 files changed, 191 insertions(+), 15 deletions(-) diff --git a/.github/workflows/deploy-cn-landing.yml b/.github/workflows/deploy-cn-landing.yml index 29d047a2..74191b10 100644 --- a/.github/workflows/deploy-cn-landing.yml +++ b/.github/workflows/deploy-cn-landing.yml @@ -31,6 +31,7 @@ on: options: - deploy - health-check + - setup-ssl concurrency: group: cn-landing-deploy @@ -123,11 +124,13 @@ jobs: cp server/nginx/cn-domain.conf /tmp/cn-domain.conf if [ -n "$ZY_CN_DOMAIN" ]; then - sed -i "s/ZY_CN_DOMAIN_PLACEHOLDER/${ZY_CN_DOMAIN}/g" /tmp/cn-domain.conf - echo "✅ 国内域名已注入: ${ZY_CN_DOMAIN}" + # 去除可能的 www. 前缀,获取裸域名 + BARE_DOMAIN="${ZY_CN_DOMAIN#www.}" + sed -i "s/ZY_CN_BARE_DOMAIN_PLACEHOLDER/${BARE_DOMAIN}/g" /tmp/cn-domain.conf + echo "✅ 国内域名已注入: ${BARE_DOMAIN} + www.${BARE_DOMAIN}" else echo "⚠️ ZY_CN_DOMAIN 未配置,使用IP直接访问" - sed -i "s/ZY_CN_DOMAIN_PLACEHOLDER/_/g" /tmp/cn-domain.conf + sed -i "s/ZY_CN_BARE_DOMAIN_PLACEHOLDER www.ZY_CN_BARE_DOMAIN_PLACEHOLDER/_/g" /tmp/cn-domain.conf fi scp -F ~/.ssh/config \ @@ -157,8 +160,11 @@ jobs: echo "✅ 四大国内模型API密钥已注入" - name: 🔧 启用Nginx配置 & 重载 + env: + ZY_CN_DOMAIN: ${{ secrets.ZY_CN_DOMAIN }} run: | - ssh cn-target << 'NGINX_CMD' + BARE_DOMAIN="${ZY_CN_DOMAIN#www.}" + ssh cn-target << NGINX_CMD set -e echo "═══ Nginx 配置诊断 ═══" @@ -178,9 +184,9 @@ jobs: # 清理 sites-enabled 中的冲突 for conf in /etc/nginx/sites-enabled/*; do - if [ -f "$conf" ] && [ "$(basename "$conf")" != "cn-domain.conf" ]; then - echo " 🗑️ 移除sites-enabled冲突: $(basename "$conf")" - sudo rm -f "$conf" + if [ -f "\$conf" ] && [ "\$(basename "\$conf")" != "cn-domain.conf" ]; then + echo " 🗑️ 移除sites-enabled冲突: \$(basename "\$conf")" + sudo rm -f "\$conf" fi done @@ -188,9 +194,9 @@ jobs: # 保留 conf.d 中的全局配置(如 gzip, ssl_params 等) # 只移除包含 server { 或 proxy_pass 的自定义站点配置 for conf in /etc/nginx/conf.d/*.conf; do - if [ -f "$conf" ] && grep -qE "server[[:space:]]*\{" "$conf" 2>/dev/null; then - echo " 🗑️ 移除conf.d冲突站点配置: $(basename "$conf")" - sudo rm -f "$conf" + if [ -f "\$conf" ] && grep -qE "server[[:space:]]*\{" "\$conf" 2>/dev/null; then + echo " 🗑️ 移除conf.d冲突站点配置: \$(basename "\$conf")" + sudo rm -f "\$conf" fi done @@ -198,6 +204,23 @@ jobs: sudo cp /opt/zhuyuan-cn/config/nginx/cn-domain.conf /etc/nginx/sites-available/cn-domain.conf sudo ln -sf /etc/nginx/sites-available/cn-domain.conf /etc/nginx/sites-enabled/cn-domain.conf + # ─── SSL自动注入: 检测已有Let's Encrypt证书 ─── + # 如果之前运行过 setup-ssl,证书文件会存在 + # 每次deploy都重新注入SSL配置,避免模板覆盖导致SSL丢失 + BARE="${BARE_DOMAIN}" + if [ -d "/etc/letsencrypt/live/\${BARE}" ] && [ -f "/etc/letsencrypt/live/\${BARE}/fullchain.pem" ]; then + echo "" + echo "§2.5 🔐 检测到SSL证书,注入HTTPS配置..." + # 在 listen 80 后添加 listen 443 ssl 和证书配置 + sudo sed -i '/listen 80 default_server;/a\\n listen 443 ssl default_server;\n ssl_certificate /etc/letsencrypt/live/'"\${BARE}"'/fullchain.pem;\n ssl_certificate_key /etc/letsencrypt/live/'"\${BARE}"'/privkey.pem;\n include /etc/letsencrypt/options-ssl-nginx.conf;\n ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;' \ + /etc/nginx/sites-available/cn-domain.conf + echo "✅ SSL配置已注入 · HTTPS已启用" + else + echo "" + echo "§2.5 ℹ️ 未检测到SSL证书 · 仅HTTP模式" + echo " 运行 setup-ssl 动作安装Let's Encrypt证书" + fi + # 确认最终状态 echo "" echo "§3 清理后sites-enabled目录:" @@ -384,8 +407,125 @@ jobs: echo "§9 端口80监听进程:" sudo ss -tlnp | grep ':80 ' 2>/dev/null || echo " (无)" + # SSL状态检查 + echo "" + echo "§10 SSL证书状态:" + sudo certbot certificates 2>/dev/null || echo " certbot未安装 · 运行setup-ssl动作安装" + + echo "" + echo "§11 HTTPS访问测试:" + HTTPS_CODE=$(curl -sf -o /dev/null -w '%{http_code}' https://localhost/ -k 2>/dev/null || echo "000") + echo "HTTPS状态码: ${HTTPS_CODE}" + HEALTH_CMD - name: 🧹 清理SSH密钥 if: always() run: rm -f ~/.ssh/id_sg ~/.ssh/id_cn ~/.ssh/config + + setup-ssl: + name: 🔐 安装SSL证书 (Let's Encrypt) + if: github.event.inputs.action == 'setup-ssl' + 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: 🔐 安装certbot并申请证书 + env: + ZY_CN_DOMAIN: ${{ secrets.ZY_CN_DOMAIN }} + run: | + BARE_DOMAIN="${ZY_CN_DOMAIN#www.}" + echo "🔐 为 ${BARE_DOMAIN} + www.${BARE_DOMAIN} 申请SSL证书..." + + ssh cn-target << SSLCMD + set -e + + echo "═══ SSL证书安装 ═══" + + # 安装certbot (如果未安装) + if ! command -v certbot &> /dev/null; then + echo "📦 安装certbot..." + sudo apt-get update -qq + sudo apt-get install -y -qq certbot python3-certbot-nginx + else + echo "✅ certbot已安装: \$(certbot --version 2>&1)" + fi + + # 确认Nginx正在运行 + if ! systemctl is-active --quiet nginx; then + echo "❌ Nginx未运行,先启动Nginx" + sudo systemctl start nginx + fi + + # 申请证书 (--nginx模式会自动修改Nginx配置) + echo "" + echo "§1 申请Let's Encrypt证书..." + sudo certbot --nginx \ + -d ${BARE_DOMAIN} \ + -d www.${BARE_DOMAIN} \ + --non-interactive \ + --agree-tos \ + --email admin@${BARE_DOMAIN} \ + --redirect \ + --no-eff-email + + # 验证证书 + echo "" + echo "§2 验证证书..." + sudo certbot certificates + + # 验证HTTPS可访问 + echo "" + echo "§3 HTTPS访问测试..." + HTTP_CODE=\$(curl -sf -o /dev/null -w '%{http_code}' https://localhost/ -k 2>/dev/null || echo "000") + echo "HTTPS状态码: \${HTTP_CODE}" + + # 验证HTTP→HTTPS重定向 + echo "" + echo "§4 HTTP→HTTPS重定向测试..." + REDIR_CODE=\$(curl -sf -o /dev/null -w '%{http_code}' http://localhost/ 2>/dev/null || echo "000") + echo "HTTP重定向码: \${REDIR_CODE} (301=正确重定向)" + + echo "" + echo "═══ SSL安装完成 ═══" + echo "🌐 现在可以通过 https://${BARE_DOMAIN} 访问" + SSLCMD + + - name: 🧹 清理SSH密钥 + if: always() + run: rm -f ~/.ssh/id_sg ~/.ssh/id_cn ~/.ssh/config \ No newline at end of file diff --git a/.github/workflows/deploy-to-zhuyuan-server.yml b/.github/workflows/deploy-to-zhuyuan-server.yml index e73f351c..659486cf 100644 --- a/.github/workflows/deploy-to-zhuyuan-server.yml +++ b/.github/workflows/deploy-to-zhuyuan-server.yml @@ -183,14 +183,20 @@ jobs: - name: 🌐 同步前端内容到站点 run: | - TARGET="${{ github.event.inputs.deploy_target || 'preview' }}" + # Push事件: 直接部署到 production (guanghulab.online = ZY_DOMAIN_MAIN = production) + # 手动触发: 使用选定的目标 (默认 preview) + if [ "${{ github.event_name }}" = "push" ]; then + TARGET="production" + else + TARGET="${{ github.event.inputs.deploy_target || 'preview' }}" + fi TARGET_DIR="/opt/zhuyuan/sites/${TARGET}" echo "🌐 同步前端 → ${TARGET_DIR}" # 确保零点原核频道目录存在 ssh -i ~/.ssh/zy_key \ ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }} \ - "mkdir -p /opt/zhuyuan/sites/yaoming" + "mkdir -p /opt/zhuyuan/sites/yaoming /opt/zhuyuan/sites/production /opt/zhuyuan/sites/preview" # 同步主站门户 (server/sites/portal/) 到目标站点目录 if [ -d "server/sites/portal" ]; then @@ -199,6 +205,15 @@ jobs: server/sites/portal/ \ ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }}:${TARGET_DIR}/ echo "✅ 主站门户已部署到 ${TARGET_DIR}" + + # Push事件额外同步到 preview 保持两站一致 + if [ "${{ github.event_name }}" = "push" ]; then + rsync -avz --delete \ + -e "ssh -i ~/.ssh/zy_key" \ + server/sites/portal/ \ + ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }}:/opt/zhuyuan/sites/preview/ + echo "✅ 主站门户已同步到 preview (保持一致)" + fi else # 降级: 使用 docs/ 目录 rsync -avz --delete \ diff --git a/server/nginx/cn-domain.conf b/server/nginx/cn-domain.conf index b22bb41b..e5061e90 100644 --- a/server/nginx/cn-domain.conf +++ b/server/nginx/cn-domain.conf @@ -8,17 +8,22 @@ # 版权: 国作登字-2026-A-00037559 # # 架构: -# ZY_CN_DOMAIN (www.guanghulab.com) → 国内用户首页 +# ZY_CN_DOMAIN (guanghulab.com / www.guanghulab.com) → 国内用户首页 # 前端: /opt/zhuyuan-cn/sites/cn-landing/ (静态HTML) # 用途: ICP备案合规 + 未来国内语言操作系统入口 # # 域名变量由 GitHub Secrets 注入: -# ZY_CN_DOMAIN — 国内备案域名 +# ZY_CN_DOMAIN — 国内备案域名 (裸域名,如 guanghulab.com) +# 部署时自动展开为: guanghulab.com + www.guanghulab.com +# +# SSL: 首次部署后运行 setup-ssl 动作安装Let's Encrypt证书 +# certbot会自动添加443监听 + HTTP→HTTPS重定向 +# 后续deploy会检测已有证书并重新注入SSL配置 # ═══════════════════════════════════════════════════════════ server { listen 80 default_server; - server_name ZY_CN_DOMAIN_PLACEHOLDER; + server_name ZY_CN_BARE_DOMAIN_PLACEHOLDER www.ZY_CN_BARE_DOMAIN_PLACEHOLDER; # ─── 安全头 ─── add_header X-Frame-Options "SAMEORIGIN" always; diff --git a/server/nginx/zhuyuan-sovereign.conf b/server/nginx/zhuyuan-sovereign.conf index e8deac4f..87eb0086 100644 --- a/server/nginx/zhuyuan-sovereign.conf +++ b/server/nginx/zhuyuan-sovereign.conf @@ -85,11 +85,18 @@ server { # 聊天请求由主应用的 domestic-llm-gateway 智能路由处理 # 支持 DeepSeek/千问/Moonshot/智谱 四路自动降级 location /api/chat { + # CORS · 允许前端跨域调用 + add_header Access-Control-Allow-Origin * always; + add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always; + add_header Access-Control-Allow-Headers "Content-Type, Authorization" always; + if ($request_method = OPTIONS) { return 204; } + proxy_pass http://127.0.0.1:3800/api/chat; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Connection ""; proxy_buffering off; proxy_cache off; @@ -247,9 +254,18 @@ server { # ─── AI 聊天 API (端口 3801) · 预览站共享主应用聊天引擎 ─── location /api/chat { + # CORS · 允许前端跨域调用 + add_header Access-Control-Allow-Origin * always; + add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always; + add_header Access-Control-Allow-Headers "Content-Type, Authorization" always; + if ($request_method = OPTIONS) { return 204; } + proxy_pass http://127.0.0.1:3801/api/chat; proxy_http_version 1.1; proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Connection ""; proxy_buffering off; proxy_cache off;