diff --git a/.github/workflows/deploy-awen-domain-proxy.yml b/.github/workflows/deploy-awen-domain-proxy.yml new file mode 100644 index 00000000..df58162d --- /dev/null +++ b/.github/workflows/deploy-awen-domain-proxy.yml @@ -0,0 +1,473 @@ +name: '🌐 Awen域名反向代理 · 部署与监控' + +# ═══════════════════════════════════════════════════════════ +# Awen 域名反向代理部署工作流 +# 编号: ZY-WF-AWEN-PROXY +# 守护: 铸渊 · ICE-GL-ZY001 +# 版权: 国作登字-2026-A-00037559 +# +# 架构: +# 用户 → Awen域名(DNS→新加坡) → ZY-SVR-002 Nginx → Awen广州后端 +# +# 功能: +# 1. deploy — 部署/更新 Nginx 反向代理配置到 ZY-SVR-002 +# 2. setup-ssl — 为 Awen 域名申请 Let's Encrypt SSL 证书 +# 3. health — 检查代理链路健康状态(代理→后端→SSL) +# 4. rollback — 回滚到上一份 Nginx 配置 +# +# 所需 GitHub Secrets: +# ZY_SERVER_HOST — ZY-SVR-002 新加坡服务器 IP +# ZY_SERVER_KEY — ZY-SVR-002 SSH 私钥 +# ZY_SERVER_USER — ZY-SVR-002 SSH 用户名 +# AWEN_DOMAIN — Awen 的域名 (如: example.com) +# AWEN_BACKEND_HOST — Awen 广州服务器 IP +# AWEN_BACKEND_PORT — Awen 后端服务端口 (默认 80) +# ═══════════════════════════════════════════════════════════ + +on: + push: + branches: [main] + paths: + - 'server/nginx/awen-domain-proxy.conf' + workflow_dispatch: + inputs: + action: + description: '执行动作' + required: true + default: 'deploy' + type: choice + options: + - deploy + - setup-ssl + - health + - rollback + +concurrency: + group: awen-domain-proxy + cancel-in-progress: false + +permissions: + contents: read + issues: write + +jobs: + # ═══ §1 部署 Nginx 反向代理配置 ═══ + deploy: + name: '🚀 部署反向代理' + if: > + github.event.inputs.action == 'deploy' || + github.event.inputs.action == '' || + github.event_name == 'push' + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v4 + + - name: '🔍 检查必要 Secrets' + env: + AWEN_DOMAIN: ${{ secrets.AWEN_DOMAIN }} + AWEN_BACKEND_HOST: ${{ secrets.AWEN_BACKEND_HOST }} + ZY_SERVER_HOST: ${{ secrets.ZY_SERVER_HOST }} + run: | + MISSING="" + [ -z "$AWEN_DOMAIN" ] && MISSING="${MISSING}AWEN_DOMAIN " + [ -z "$AWEN_BACKEND_HOST" ] && MISSING="${MISSING}AWEN_BACKEND_HOST " + [ -z "$ZY_SERVER_HOST" ] && MISSING="${MISSING}ZY_SERVER_HOST " + if [ -n "$MISSING" ]; then + echo "❌ 缺少必要的 GitHub Secrets: $MISSING" + echo "" + echo "═══ 配置指南 ═══" + echo "请在仓库 Settings → Secrets → Actions 中添加:" + echo " AWEN_DOMAIN — Awen的域名 (如: example.com)" + echo " AWEN_BACKEND_HOST — Awen广州服务器IP" + echo " AWEN_BACKEND_PORT — 后端端口 (默认80,可选)" + echo " ZY_SERVER_HOST — 新加坡服务器IP (ZY-SVR-002)" + echo " ZY_SERVER_KEY — 新加坡服务器SSH私钥" + echo " ZY_SERVER_USER — 新加坡服务器SSH用户名" + exit 1 + fi + echo "✅ 所有必要 Secrets 已配置" + + - name: '🔐 配置SSH' + env: + SSH_KEY: ${{ secrets.ZY_SERVER_KEY }} + run: | + mkdir -p ~/.ssh + echo "$SSH_KEY" > ~/.ssh/zy_key + chmod 600 ~/.ssh/zy_key + if head -1 ~/.ssh/zy_key | grep -q "BEGIN" && tail -1 ~/.ssh/zy_key | grep -q "END"; then + echo "✅ SSH私钥格式正确" + else + echo "❌ SSH私钥格式异常" + exit 1 + fi + ssh-keyscan -H ${{ secrets.ZY_SERVER_HOST }} >> ~/.ssh/known_hosts 2>/dev/null + + - name: '🔍 SSH连接测试' + run: | + ssh -i ~/.ssh/zy_key -o BatchMode=yes -o ConnectTimeout=10 \ + ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }} \ + 'echo "✅ SSH连接成功 · $(hostname) · $(date)"' + + - name: '📦 生成并部署 Nginx 配置' + env: + AWEN_DOMAIN: ${{ secrets.AWEN_DOMAIN }} + AWEN_BACKEND_HOST: ${{ secrets.AWEN_BACKEND_HOST }} + AWEN_BACKEND_PORT: ${{ secrets.AWEN_BACKEND_PORT }} + run: | + BACKEND_PORT="${AWEN_BACKEND_PORT:-80}" + + echo "═══ Awen 域名反向代理部署 ═══" + echo "域名: ${AWEN_DOMAIN}" + echo "后端: ${AWEN_BACKEND_HOST}:${BACKEND_PORT}" + echo "代理服务器: ZY-SVR-002 (新加坡)" + echo "" + + # 复制模板并注入实际值 + cp server/nginx/awen-domain-proxy.conf /tmp/awen-domain-proxy.conf + sed -i "s/AWEN_DOMAIN_PLACEHOLDER/${AWEN_DOMAIN}/g" /tmp/awen-domain-proxy.conf + sed -i "s/AWEN_BACKEND_HOST_PLACEHOLDER/${AWEN_BACKEND_HOST}/g" /tmp/awen-domain-proxy.conf + sed -i "s/AWEN_BACKEND_PORT_PLACEHOLDER/${BACKEND_PORT}/g" /tmp/awen-domain-proxy.conf + + echo "📋 生成的配置:" + cat /tmp/awen-domain-proxy.conf + echo "" + + # 检查主配置是否已有 connection_upgrade map + # 如果有则移除本配置中的 map 块避免冲突 + HAS_MAP=$(ssh -i ~/.ssh/zy_key \ + ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }} \ + "grep -l 'map.*http_upgrade.*connection_upgrade' /etc/nginx/nginx.conf /etc/nginx/conf.d/*.conf /etc/nginx/sites-available/*.conf 2>/dev/null | head -1" || true) + + if [ -n "$HAS_MAP" ]; then + echo "ℹ️ 主配置已包含 connection_upgrade map,移除本配置中的重复定义" + sed -i '/^# ─── WebSocket 升级映射/,/^}$/d' /tmp/awen-domain-proxy.conf + sed -i '/^map \$http_upgrade/,/^}$/d' /tmp/awen-domain-proxy.conf + fi + + # 备份现有配置(如果存在) + ssh -i ~/.ssh/zy_key \ + ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }} \ + "if [ -f /etc/nginx/sites-available/awen-proxy.conf ]; then + sudo cp /etc/nginx/sites-available/awen-proxy.conf \ + /etc/nginx/sites-available/awen-proxy.conf.bak.\$(date +%Y%m%d%H%M%S) + echo '✅ 已备份现有配置' + fi + sudo mkdir -p /opt/zhuyuan/data/logs /var/www/certbot" + + # 上传配置 + scp -i ~/.ssh/zy_key \ + /tmp/awen-domain-proxy.conf \ + ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }}:/tmp/awen-domain-proxy.conf + + # 安装并启用配置 + ssh -i ~/.ssh/zy_key \ + ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }} << 'DEPLOY_CMD' + + set -e + + # 安装配置 + sudo cp /tmp/awen-domain-proxy.conf /etc/nginx/sites-available/awen-proxy.conf + sudo ln -sf /etc/nginx/sites-available/awen-proxy.conf /etc/nginx/sites-enabled/awen-proxy.conf + + # 验证 Nginx 配置 + echo "🔍 验证 Nginx 配置..." + if sudo nginx -t 2>&1; then + echo "✅ Nginx 配置验证通过" + sudo systemctl reload nginx + echo "✅ Nginx 已重载" + else + echo "❌ Nginx 配置验证失败" + # 回滚 + sudo rm -f /etc/nginx/sites-enabled/awen-proxy.conf + LATEST_BAK=$(ls -t /etc/nginx/sites-available/awen-proxy.conf.bak.* 2>/dev/null | head -1) + if [ -n "$LATEST_BAK" ]; then + sudo cp "$LATEST_BAK" /etc/nginx/sites-available/awen-proxy.conf + sudo ln -sf /etc/nginx/sites-available/awen-proxy.conf /etc/nginx/sites-enabled/awen-proxy.conf + sudo nginx -t && sudo systemctl reload nginx + echo "↩️ 已回滚到上一份配置" + fi + exit 1 + fi + + DEPLOY_CMD + + - name: '💚 部署后健康检查' + env: + AWEN_DOMAIN: ${{ secrets.AWEN_DOMAIN }} + AWEN_BACKEND_HOST: ${{ secrets.AWEN_BACKEND_HOST }} + AWEN_BACKEND_PORT: ${{ secrets.AWEN_BACKEND_PORT }} + run: | + BACKEND_PORT="${AWEN_BACKEND_PORT:-80}" + echo "═══ 部署后健康检查 ═══" + echo "" + + # 检查 Nginx 是否正常 + ssh -i ~/.ssh/zy_key \ + ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }} \ + "systemctl is-active nginx && echo '✅ Nginx运行中' || echo '❌ Nginx未运行'" + + # 检查域名 HTTP 响应 + sleep 2 + HTTP_CODE=$(curl -sf -o /dev/null -w "%{http_code}" \ + --resolve "${AWEN_DOMAIN}:80:${{ secrets.ZY_SERVER_HOST }}" \ + "http://${AWEN_DOMAIN}/" 2>/dev/null || echo "000") + echo "HTTP 状态码 (通过代理): ${HTTP_CODE}" + + if [ "$HTTP_CODE" = "000" ] || [ "$HTTP_CODE" = "502" ]; then + echo "⚠️ 后端暂时不可达 (广州服务器可能未就绪)" + echo " 代理配置已部署成功,待后端上线后自动生效" + elif [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 400 ]; then + echo "✅ 代理链路正常" + else + echo "⚠️ 状态码 ${HTTP_CODE} — 请检查后端服务" + fi + + # ═══ §2 SSL证书申请 ═══ + setup-ssl: + name: '🔒 SSL证书配置' + if: github.event.inputs.action == 'setup-ssl' + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v4 + + - name: '🔐 配置SSH' + env: + SSH_KEY: ${{ secrets.ZY_SERVER_KEY }} + run: | + mkdir -p ~/.ssh + echo "$SSH_KEY" > ~/.ssh/zy_key + chmod 600 ~/.ssh/zy_key + ssh-keyscan -H ${{ secrets.ZY_SERVER_HOST }} >> ~/.ssh/known_hosts 2>/dev/null + + - name: '🔒 申请 Let''s Encrypt SSL 证书' + env: + AWEN_DOMAIN: ${{ secrets.AWEN_DOMAIN }} + run: | + if [ -z "$AWEN_DOMAIN" ]; then + echo "❌ AWEN_DOMAIN 未配置" + exit 1 + fi + + echo "🔒 为 ${AWEN_DOMAIN} 申请SSL证书" + echo "" + + ssh -i ~/.ssh/zy_key \ + ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }} << SSLCMD + + set -e + + # 安装 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 + fi + + # 确保 webroot 目录存在 + sudo mkdir -p /var/www/certbot + + # 申请证书(使用 webroot 模式,不中断 Nginx) + sudo certbot certonly \ + --webroot -w /var/www/certbot \ + -d ${AWEN_DOMAIN} \ + --non-interactive \ + --agree-tos \ + --email admin@${AWEN_DOMAIN} \ + --no-eff-email \ + || { + echo "⚠️ Webroot 模式失败,尝试 standalone 模式..." + sudo certbot certonly \ + --nginx \ + -d ${AWEN_DOMAIN} \ + --non-interactive \ + --agree-tos \ + --email admin@${AWEN_DOMAIN} \ + --no-eff-email + } + + echo "✅ SSL证书申请成功" + + # 更新 Nginx 配置添加 SSL + CONF="/etc/nginx/sites-available/awen-proxy.conf" + if [ -f "\$CONF" ] && ! grep -q "listen 443 ssl" "\$CONF"; then + echo "📝 使用 certbot 自动配置 SSL..." + sudo certbot --nginx -d ${AWEN_DOMAIN} --non-interactive --redirect 2>&1 || { + echo "❌ certbot --nginx 配置失败,SSL未启用" + exit 1 + } + echo "✅ SSL 已通过 certbot --nginx 启用" + else + echo "ℹ️ SSL 配置已存在或配置文件不存在" + fi + + # 设置自动续期 cron + if ! crontab -l 2>/dev/null | grep -q "certbot renew"; then + (crontab -l 2>/dev/null; echo "0 3 1 * * certbot renew --quiet --post-hook 'systemctl reload nginx'") | crontab - + echo "✅ SSL 自动续期 cron 已配置 (每月1日 03:00)" + fi + + SSLCMD + + - name: '💚 SSL验证' + env: + AWEN_DOMAIN: ${{ secrets.AWEN_DOMAIN }} + run: | + echo "🔍 验证 HTTPS: https://${AWEN_DOMAIN}" + sleep 3 + HTTP_CODE=$(curl -sf -o /dev/null -w "%{http_code}" "https://${AWEN_DOMAIN}/" 2>/dev/null || echo "000") + echo "HTTPS状态码: ${HTTP_CODE}" + if [ "$HTTP_CODE" != "000" ]; then + echo "✅ HTTPS可访问" + else + echo "⚠️ HTTPS暂时不可访问 (可能需要等待DNS传播)" + fi + + # ═══ §3 健康检查 (代理+后端+SSL) ═══ + health: + name: '💚 代理链路健康检查' + if: github.event.inputs.action == 'health' + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: actions/checkout@v4 + + - name: '🔐 配置SSH' + env: + SSH_KEY: ${{ secrets.ZY_SERVER_KEY }} + run: | + mkdir -p ~/.ssh + echo "$SSH_KEY" > ~/.ssh/zy_key + chmod 600 ~/.ssh/zy_key + ssh-keyscan -H ${{ secrets.ZY_SERVER_HOST }} >> ~/.ssh/known_hosts 2>/dev/null + + - name: '💚 全链路健康检查' + env: + AWEN_DOMAIN: ${{ secrets.AWEN_DOMAIN }} + AWEN_BACKEND_HOST: ${{ secrets.AWEN_BACKEND_HOST }} + AWEN_BACKEND_PORT: ${{ secrets.AWEN_BACKEND_PORT }} + run: | + BACKEND_PORT="${AWEN_BACKEND_PORT:-80}" + echo "═══ Awen 域名代理 · 健康检查报告 ═══" + echo "时间: $(date -u '+%Y-%m-%d %H:%M:%S UTC')" + echo "" + + ISSUES="" + + # §1 代理服务器 Nginx 状态 + echo "§1 代理服务器 (ZY-SVR-002 · 新加坡)" + ssh -i ~/.ssh/zy_key -o ConnectTimeout=10 \ + ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }} << 'HEALTH' || { + echo "❌ 无法连接到代理服务器" + ISSUES="${ISSUES}proxy_ssh_fail " + } + + echo " Nginx: $(systemctl is-active nginx 2>/dev/null || echo 'unknown')" + echo " 配置: $([ -f /etc/nginx/sites-enabled/awen-proxy.conf ] && echo '✅ 已启用' || echo '❌ 未启用')" + echo " 日志行数: $(wc -l < /opt/zhuyuan/data/logs/nginx-awen-proxy.log 2>/dev/null || echo 'N/A')" + + # 检查 SSL 证书有效期 + if [ -f /etc/letsencrypt/live/${AWEN_DOMAIN}/fullchain.pem ]; then + EXPIRY=$(openssl x509 -enddate -noout -in /etc/letsencrypt/live/${AWEN_DOMAIN}/fullchain.pem 2>/dev/null | cut -d= -f2) + echo " SSL证书到期: ${EXPIRY:-unknown}" + else + echo " SSL证书: 未配置" + fi + + HEALTH + + echo "" + + # §2 后端可达性 (从代理服务器测试) + echo "§2 后端服务器 (Awen · 广州)" + if [ -n "$AWEN_BACKEND_HOST" ]; then + BACKEND_CODE=$(ssh -i ~/.ssh/zy_key \ + ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }} \ + "curl -sf -o /dev/null -w '%{http_code}' --connect-timeout 10 \ + http://${AWEN_BACKEND_HOST}:${BACKEND_PORT}/health 2>/dev/null || echo '000'" || echo "000") + echo " 健康端点: ${BACKEND_CODE}" + if [ "$BACKEND_CODE" = "000" ]; then + echo " ❌ 后端不可达" + ISSUES="${ISSUES}backend_unreachable " + elif [ "$BACKEND_CODE" -ge 200 ] && [ "$BACKEND_CODE" -lt 400 ]; then + echo " ✅ 后端正常" + else + echo " ⚠️ 后端异常 (${BACKEND_CODE})" + ISSUES="${ISSUES}backend_error " + fi + else + echo " ⏳ AWEN_BACKEND_HOST 未配置" + fi + + echo "" + + # §3 端到端测试 (通过域名访问) + echo "§3 端到端测试 (通过域名)" + if [ -n "$AWEN_DOMAIN" ]; then + # HTTP + E2E_HTTP=$(curl -sf -o /dev/null -w "%{http_code}" \ + --resolve "${AWEN_DOMAIN}:80:${{ secrets.ZY_SERVER_HOST }}" \ + "http://${AWEN_DOMAIN}/" 2>/dev/null || echo "000") + echo " HTTP: ${E2E_HTTP}" + + # HTTPS + E2E_HTTPS=$(curl -sf -o /dev/null -w "%{http_code}" \ + "https://${AWEN_DOMAIN}/" 2>/dev/null || echo "000") + echo " HTTPS: ${E2E_HTTPS}" + else + echo " ⏳ AWEN_DOMAIN 未配置" + fi + + echo "" + echo "═══ 检查完成 ═══" + + # 如果有严重问题,退出非0(可触发通知) + if echo "$ISSUES" | grep -q "proxy_ssh_fail\|backend_unreachable"; then + echo "" + echo "⚠️ 发现问题: $ISSUES" + exit 1 + fi + + # ═══ §4 回滚 ═══ + rollback: + name: '↩️ 回滚配置' + if: github.event.inputs.action == 'rollback' + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: actions/checkout@v4 + + - name: '🔐 配置SSH' + env: + SSH_KEY: ${{ secrets.ZY_SERVER_KEY }} + run: | + mkdir -p ~/.ssh + echo "$SSH_KEY" > ~/.ssh/zy_key + chmod 600 ~/.ssh/zy_key + ssh-keyscan -H ${{ secrets.ZY_SERVER_HOST }} >> ~/.ssh/known_hosts 2>/dev/null + + - name: '↩️ 回滚到上一份配置' + run: | + ssh -i ~/.ssh/zy_key \ + ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }} << 'ROLLBACK' + + LATEST_BAK=$(ls -t /etc/nginx/sites-available/awen-proxy.conf.bak.* 2>/dev/null | head -1) + if [ -n "$LATEST_BAK" ]; then + echo "↩️ 回滚到: $LATEST_BAK" + sudo cp "$LATEST_BAK" /etc/nginx/sites-available/awen-proxy.conf + if sudo nginx -t 2>&1; then + sudo systemctl reload nginx + echo "✅ 回滚成功" + else + echo "❌ 回滚后配置仍无效" + sudo rm -f /etc/nginx/sites-enabled/awen-proxy.conf + sudo nginx -t && sudo systemctl reload nginx + echo "⚠️ 已禁用 Awen 代理配置" + fi + else + echo "❌ 没有可回滚的备份" + exit 1 + fi + + ROLLBACK diff --git a/server/nginx/awen-domain-proxy.conf b/server/nginx/awen-domain-proxy.conf new file mode 100644 index 00000000..05b08f2c --- /dev/null +++ b/server/nginx/awen-domain-proxy.conf @@ -0,0 +1,110 @@ +# ═══════════════════════════════════════════════════════════ +# Awen 域名反向代理配置 · 新加坡中转 +# ═══════════════════════════════════════════════════════════ +# +# 编号: ZY-SVR-NGX-AWEN +# 中转服务器: ZY-SVR-002 (43.134.16.246 · 新加坡) +# 后端服务器: ZY-SVR-AWEN (广州 · Awen实际服务) +# 守护: 铸渊 · ICE-GL-ZY001 +# 版权: 国作登字-2026-A-00037559 +# +# 架构: +# 用户浏览器 → Awen域名(DNS→新加坡IP) +# → ZY-SVR-002 Nginx(本配置·反向代理) +# → Awen广州服务器(实际服务) +# +# 域名未备案解决方案: +# 域名DNS A记录指向新加坡IP → 无需中国大陆ICP备案 +# 新加坡Nginx将请求反向代理到广州后端 +# 延迟约30-50ms · 对Web应用可接受 +# +# 占位符由 deploy workflow 自动替换: +# AWEN_DOMAIN_PLACEHOLDER ← GitHub Secret: AWEN_DOMAIN +# AWEN_BACKEND_HOST_PLACEHOLDER ← GitHub Secret: AWEN_BACKEND_HOST +# AWEN_BACKEND_PORT_PLACEHOLDER ← GitHub Secret: AWEN_BACKEND_PORT +# ═══════════════════════════════════════════════════════════ + +# ─── Awen 域名 · 反向代理到广州后端 ─── +server { + listen 80; + server_name AWEN_DOMAIN_PLACEHOLDER; + + # ─── 安全头 ─── + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-XSS-Protection "1; mode=block" always; + add_header X-Server-Identity "ZY-SVR-002" always; + add_header X-Proxy-Mode "awen-reverse-proxy" always; + + # ─── 请求体大小限制 (允许文件上传) ─── + client_max_body_size 50m; + + # ─── 主路由 · 反向代理到广州后端 ─── + location / { + proxy_pass http://AWEN_BACKEND_HOST_PLACEHOLDER:AWEN_BACKEND_PORT_PLACEHOLDER; + 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 X-Forwarded-Host $host; + + # ─── WebSocket 支持 ─── + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + + # ─── 超时设置 (跨境延迟考虑 · 新加坡↔广州) ─── + proxy_connect_timeout 15s; + proxy_read_timeout 120s; + proxy_send_timeout 60s; + + # ─── 缓冲设置 ─── + proxy_buffering on; + proxy_buffer_size 16k; + proxy_buffers 4 32k; + proxy_busy_buffers_size 64k; + + # ─── 错误处理 · 后端不可达时返回友好页面 ─── + proxy_intercept_errors on; + error_page 502 503 504 /awen_backend_unavailable.html; + } + + # ─── 健康检查端点 (不记录日志 · 减少噪音) ─── + location = /health { + proxy_pass http://AWEN_BACKEND_HOST_PLACEHOLDER:AWEN_BACKEND_PORT_PLACEHOLDER/health; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_connect_timeout 5s; + proxy_read_timeout 10s; + access_log off; + } + + # ─── Let's Encrypt 证书验证路径 ─── + location /.well-known/acme-challenge/ { + root /var/www/certbot; + allow all; + } + + # ─── 后端不可达时的友好错误页 ─── + location = /awen_backend_unavailable.html { + internal; + default_type text/html; + return 502 'Service Temporarily Unavailable

503 Service Temporarily Unavailable

The backend server is currently unreachable. Please try again later.

Proxy: ZY-SVR-002 (Singapore) → Backend: Guangzhou

'; + } + + # ─── 访问日志 · 独立文件便于监控 ─── + access_log /opt/zhuyuan/data/logs/nginx-awen-proxy.log; + error_log /opt/zhuyuan/data/logs/nginx-awen-proxy-error.log; +} + +# ─── WebSocket 升级映射 ─── +# 注意: 此 map 块必须位于 http {} 上下文 (不在 server {} 内) +# 如果 nginx.conf 或其他配置文件已定义 $connection_upgrade, +# 部署 workflow 会自动检测并移除本段避免冲突 +map $http_upgrade $connection_upgrade { + default upgrade; + '' close; +} diff --git a/server/proxy/config/server-registry.json b/server/proxy/config/server-registry.json index 2eb3da5c..4252ff63 100644 --- a/server/proxy/config/server-registry.json +++ b/server/proxy/config/server-registry.json @@ -2,8 +2,8 @@ "_sovereign": "TCS-0002∞ | SYS-GLW-0001", "_copyright": "国作登字-2026-A-00037559", "_description": "光湖语言世界 · 四台服务器注册表", - "version": "1.0", - "updated_at": "2026-04-07", + "version": "1.1", + "updated_at": "2026-04-10", "servers": [ { "id": "ZY-SVR-002", @@ -14,6 +14,7 @@ "status": "active", "services": [ "nginx (静态文件·主站+预览站)", + "nginx (Awen域名反向代理·新加坡→广州)", "xray (VLESS+Reality VPN)", "api (端口3800·主站)", "api-preview (端口3801·预览站)", @@ -88,6 +89,20 @@ "notes": "Awen下载完整仓库后部署·铸渊主控自动唤醒" } ], + "domain_proxy": { + "description": "域名未备案反向代理 · 新加坡中转架构", + "architecture": "用户 → 域名(DNS→SG) → ZY-SVR-002 Nginx → 广州后端", + "proxy_server": "ZY-SVR-002", + "domains": [ + { + "owner": "Awen", + "config_file": "server/nginx/awen-domain-proxy.conf", + "workflow": ".github/workflows/deploy-awen-domain-proxy.yml", + "secrets_required": ["AWEN_DOMAIN", "AWEN_BACKEND_HOST", "AWEN_BACKEND_PORT"], + "status": "pending" + } + ] + }, "bandwidth_strategy": { "description": "四台服务器按用途分流·带宽最大化", "routing": { @@ -98,7 +113,8 @@ "claude_api_relay": "ZY-SVR-SV", "international_api": "ZY-SVR-SV", "awen_team": "ZY-SVR-AWEN", - "zhiqiu_persona": "ZY-SVR-AWEN" + "zhiqiu_persona": "ZY-SVR-AWEN", + "awen_domain_proxy": "ZY-SVR-002 → ZY-SVR-AWEN" } } } diff --git a/team-integration-v4/awen-tech-hub/domain-registry.json b/team-integration-v4/awen-tech-hub/domain-registry.json index 3f23cd41..399d4b07 100644 --- a/team-integration-v4/awen-tech-hub/domain-registry.json +++ b/team-integration-v4/awen-tech-hub/domain-registry.json @@ -51,7 +51,24 @@ "server_code": null, "dns_provider": null, "architecture_role": "技术主控台·待配置", - "status": "pending" + "status": "pending", + "reverse_proxy": { + "enabled": true, + "proxy_server": "ZY-SVR-002 (新加坡)", + "backend_server": "ZY-SVR-AWEN (广州)", + "reason": "域名未备案·通过新加坡服务器反向代理·免备案", + "config_file": "server/nginx/awen-domain-proxy.conf", + "deploy_workflow": ".github/workflows/deploy-awen-domain-proxy.yml", + "setup_steps": [ + "1. 配置 GitHub Secret: AWEN_DOMAIN (Awen的域名)", + "2. 配置 GitHub Secret: AWEN_BACKEND_HOST (广州服务器IP)", + "3. 配置 GitHub Secret: AWEN_BACKEND_PORT (后端端口·默认80)", + "4. Awen将域名DNS A记录指向新加坡服务器IP (ZY-SVR-002)", + "5. 运行 workflow: deploy-awen-domain-proxy → deploy", + "6. 运行 workflow: deploy-awen-domain-proxy → setup-ssl", + "7. 广州服务器防火墙白名单添加新加坡IP" + ] + } } ],