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 "" # 备份现有配置(如果存在) 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