fix: guanghulab.com无法打开 + guanghulab.online API不通

根因修复:
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>
This commit is contained in:
copilot-swe-agent[bot] 2026-04-12 00:21:22 +00:00 committed by GitHub
parent bf3dee555b
commit 6de783ad4f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 191 additions and 15 deletions

View File

@ -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

View File

@ -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 \

View File

@ -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;

View File

@ -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;