guanghulab/.github/workflows/deploy-awen-domain-proxy.yml
2026-05-10 13:12:44 +08:00

462 lines
17 KiB
YAML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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