name: '๐Ÿ“š ๅ…‰ๆน–ๆ™บๅบ“ ยท guanghu.online ้ƒจ็ฝฒ' # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• # ๅ…‰ๆน–ๆ™บๅบ“่Š‚็‚น็‹ฌ็ซ‹้ƒจ็ฝฒๅทฅไฝœๆต # ้กน็›ฎ็ผ–ๅท: ZY-PROJ-006 # ๅŸŸๅ: guanghu.online # ๆœๅŠกๅ™จ: ZY-SVR-006 (43.153.203.105 ยท ๆ–ฐๅŠ ๅก) # ๅฎˆๆŠค: ้“ธๆธŠ ยท ICE-GL-ZY001 # ็‰ˆๆƒ: ๅ›ฝไฝœ็™ปๅญ—-2026-A-00037559 # # ๅŠŸ่ƒฝ: # 1. deploy โ€” ้ƒจ็ฝฒๅ‰็ซฏ + ๅŽ็ซฏ + Nginx + PM2 # 2. setup-ssl โ€” ็”ณ่ฏท/็ปญ็ญพ SSL ่ฏไนฆ # 3. health โ€” ๆฃ€ๆŸฅ API + ๅ‰็ซฏ่ฟ่กŒ็Šถๆ€ # 4. rollback โ€” ๅ›žๆปšๅˆฐไธŠไธ€ไปฝ้…็ฝฎ # # ๆ‰€้œ€ GitHub Secrets: # ZY_NOVEL_HOST โ€” ZY-SVR-006 IP (43.153.203.105) # ZY_NOVEL_KEY โ€” ZY-SVR-006 SSH ็ง้’ฅ # ZY_NOVEL_USER โ€” ZY-SVR-006 SSH ็”จๆˆทๅ (root) # ZY_NOVEL_JWT_SECRET โ€” JWT ็ญพๅๅฏ†้’ฅ # ZY_OSS_KEY โ€” ่…พ่ฎฏไบ‘ COS SecretId๏ผˆไป“ๅบ“ๅทฒๆœ‰ยทๆ˜ ๅฐ„ไธบ ZY_COS_SECRET_ID๏ผ‰ # ZY_OSS_SECRET โ€” ่…พ่ฎฏไบ‘ COS SecretKey๏ผˆไป“ๅบ“ๅทฒๆœ‰ยทๆ˜ ๅฐ„ไธบ ZY_COS_SECRET_KEY๏ผ‰ # ZY_NOVEL_COS_BUCKET โ€” COS ๆกถๅ๏ผˆไป“ๅบ“ๅทฒๆœ‰ยทๆ˜ ๅฐ„ไธบ ZY_COS_BUCKET๏ผ‰ # ๏ผˆZY_COS_REGION ไธไฝฟ็”จ Secret ยท ็กฌ็ผ–็  ap-singapore ยท ้ฟๅ…่ฆ†็›–ๅนฟๅทžๆกถ้…็ฝฎ๏ผ‰ # ZY_ZHIKU_DOMAIN โ€” ๅŸŸๅ (guanghu.online) # ZY_SMTP_USER โ€” SMTP ๅ‘ไปถ้‚ฎ็ฎฑ (ๅฆ‚ <<@committer_handle:base64>>) # ZY_SMTP_PASS โ€” SMTP ๅบ”็”จไธ“็”จๅฏ†็  (้ž้‚ฎ็ฎฑ็™ปๅฝ•ๅฏ†็ ) # ZY_DEEPSEEK_API_KEY โ€” DeepSeek LLM API ๅฏ†้’ฅ (Agentๅฏน่ฏ) # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• on: push: branches: [main] paths: - 'server/zhiku-node/**' - 'server/nginx/zhiku-guanghu-online.conf' workflow_dispatch: inputs: action: description: 'ๆ‰ง่กŒๅŠจไฝœ' required: true default: 'deploy' type: choice options: - deploy - setup-datasources - setup-ssl - health - rollback jobs: # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• # Job 1: ๅฎŒๆ•ด้ƒจ็ฝฒ # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• deploy: name: '๐Ÿš€ ๆ™บๅบ“่Š‚็‚น้ƒจ็ฝฒ ยท guanghu.online' runs-on: ubuntu-latest permissions: contents: read if: | github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && github.event.inputs.action == 'deploy') steps: - name: '๐Ÿ“ฅ ๆฃ€ๅ‡บไปฃ็ ' uses: actions/checkout@v4 - name: '๐Ÿ”‘ ้…็ฝฎ SSH' run: | mkdir -p ~/.ssh echo "${{ secrets.ZY_NOVEL_KEY }}" > ~/.ssh/zhiku_key chmod 600 ~/.ssh/zhiku_key ssh-keyscan -H ${{ secrets.ZY_NOVEL_HOST }} >> ~/.ssh/known_hosts - name: '๐Ÿ“ฆ ๅฎ‰่ฃ…ๆœๅŠกๅ™จๅŸบ็ก€ไพ่ต–' run: | ssh -i ~/.ssh/zhiku_key -o StrictHostKeyChecking=no \ ${{ secrets.ZY_NOVEL_USER }}@${{ secrets.ZY_NOVEL_HOST }} << 'ENDSSH' set -e # ๅฎ‰่ฃ… Node.js 20 (ๅฆ‚ๆžœ่ฟ˜ๆฒกๆœ‰) if ! command -v node &>/dev/null || [ "$(node -v | cut -d. -f1 | tr -d v)" -lt 20 ]; then curl -fsSL https://deb.nodesource.com/setup_20.x | bash - apt-get install -y nodejs fi # ๅฎ‰่ฃ… PM2 npm list -g pm2 &>/dev/null || npm install -g pm2 # ๅˆ›ๅปบ็›ฎๅฝ•็ป“ๆž„ mkdir -p /opt/zhiku/public/assets/{css,js,img} mkdir -p /opt/zhiku/public/modules mkdir -p /opt/zhiku/server mkdir -p /opt/zhiku/data/index mkdir -p /opt/zhiku/data/books mkdir -p /opt/zhiku/data/guardian mkdir -p /opt/zhiku/datasources/fqweb mkdir -p /opt/zhiku/datasources/swiftcat mkdir -p /var/log/zhiku mkdir -p /var/www/certbot echo "[ZY-SVR-006] ๅŸบ็ก€็›ฎๅฝ•ๅทฒๅฐฑ็ปช" ENDSSH - name: '๐Ÿ“ค ไธŠไผ ๅ‰็ซฏๆ–‡ไปถ' run: | scp -i ~/.ssh/zhiku_key -o StrictHostKeyChecking=no -r \ server/zhiku-node/public/* \ ${{ secrets.ZY_NOVEL_USER }}@${{ secrets.ZY_NOVEL_HOST }}:/opt/zhiku/public/ - name: '๐Ÿ“ค ไธŠไผ ๅŽ็ซฏๆ–‡ไปถ' run: | scp -i ~/.ssh/zhiku_key -o StrictHostKeyChecking=no -r \ server/zhiku-node/server/package.json \ server/zhiku-node/server/package-lock.json \ server/zhiku-node/server/server.js \ server/zhiku-node/server/.env.example \ ${{ secrets.ZY_NOVEL_USER }}@${{ secrets.ZY_NOVEL_HOST }}:/opt/zhiku/server/ - name: '๐Ÿ“ค ไธŠไผ ้•œ้ข Agent + ้•œ้˜ฒๆจกๅ— + ไนฆๅฒš Agent + ๅ†…็ฝฎๆ•ฐๆฎๆบ' run: | # ๅˆ›ๅปบ่ฟœ็จ‹็›ฎๅฝ•๏ผˆๅซ้“ธๆธŠๅ“จๅ…ต + ๆฐธไน…่ฎฐๅฟ†ๅญ˜ๅ‚จ๏ผ‰ ssh -i ~/.ssh/zhiku_key -o StrictHostKeyChecking=no \ ${{ secrets.ZY_NOVEL_USER }}@${{ secrets.ZY_NOVEL_HOST }} \ 'mkdir -p /opt/zhiku/server/mirror-agent/data/{snapshots,tickets,memory} /opt/zhiku/server/mirror-shield /opt/zhiku/server/shulan-agent /opt/zhiku/server/builtin-source /opt/zhiku/server/zhuyuan-sentinel /opt/zhiku/data/guardian /opt/zhiku/data/sentinel' # ไธŠไผ  mirror-agent scp -i ~/.ssh/zhiku_key -o StrictHostKeyChecking=no -r \ server/zhiku-node/server/mirror-agent/*.js \ ${{ secrets.ZY_NOVEL_USER }}@${{ secrets.ZY_NOVEL_HOST }}:/opt/zhiku/server/mirror-agent/ # ไธŠไผ  mirror-shield scp -i ~/.ssh/zhiku_key -o StrictHostKeyChecking=no -r \ server/zhiku-node/server/mirror-shield/*.js \ ${{ secrets.ZY_NOVEL_USER }}@${{ secrets.ZY_NOVEL_HOST }}:/opt/zhiku/server/mirror-shield/ # ไธŠไผ  shulan-agent๏ผˆไนฆๅฒšไบบๆ ผไฝ“็ณป็ปŸ๏ผ‰ scp -i ~/.ssh/zhiku_key -o StrictHostKeyChecking=no -r \ server/zhiku-node/server/shulan-agent/*.js \ ${{ secrets.ZY_NOVEL_USER }}@${{ secrets.ZY_NOVEL_HOST }}:/opt/zhiku/server/shulan-agent/ # ไธŠไผ  builtin-source๏ผˆๅ†…็ฝฎๆ•ฐๆฎๆบ็›ด่ฟž ยท ๆœ็ดขไธ‹่ฝฝfallback๏ผ‰ scp -i ~/.ssh/zhiku_key -o StrictHostKeyChecking=no -r \ server/zhiku-node/server/builtin-source/*.js \ ${{ secrets.ZY_NOVEL_USER }}@${{ secrets.ZY_NOVEL_HOST }}:/opt/zhiku/server/builtin-source/ # ไธŠไผ  zhuyuan-sentinel๏ผˆ้“ธๆธŠๅ“จๅ…ต ยท ๆฐธไน…่ฎฐๅฟ† + ไนฆๆบ่‡ชๅŠจ่ฟ็ปด๏ผ‰ scp -i ~/.ssh/zhiku_key -o StrictHostKeyChecking=no -r \ server/zhiku-node/server/zhuyuan-sentinel/*.js \ ${{ secrets.ZY_NOVEL_USER }}@${{ secrets.ZY_NOVEL_HOST }}:/opt/zhiku/server/zhuyuan-sentinel/ - name: '๐Ÿ“ค ไธŠไผ  PM2 ้…็ฝฎ' run: | scp -i ~/.ssh/zhiku_key -o StrictHostKeyChecking=no \ server/zhiku-node/ecosystem.config.js \ ${{ secrets.ZY_NOVEL_USER }}@${{ secrets.ZY_NOVEL_HOST }}:/opt/zhiku/ - name: '๐Ÿ“ค ไธŠไผ  Nginx ้…็ฝฎ' run: | scp -i ~/.ssh/zhiku_key -o StrictHostKeyChecking=no \ server/nginx/zhiku-guanghu-online.conf \ ${{ secrets.ZY_NOVEL_USER }}@${{ secrets.ZY_NOVEL_HOST }}:/etc/nginx/sites-available/zhiku - name: 'โš™๏ธ ้…็ฝฎ็Žฏๅขƒๅ˜้‡ + ๅฎ‰่ฃ…ไพ่ต– + ๅฏๅŠจๆœๅŠก' run: | ssh -i ~/.ssh/zhiku_key -o StrictHostKeyChecking=no \ ${{ secrets.ZY_NOVEL_USER }}@${{ secrets.ZY_NOVEL_HOST }} << 'ENDSSH' set -e # โ”€โ”€โ”€ ๅ†™ๅ…ฅ .env โ”€โ”€โ”€ cat > /opt/zhiku/server/.env << 'ENVEOF' PORT=3006 NODE_ENV=production ZY_ZHIKU_JWT_SECRET=${{ secrets.ZY_NOVEL_JWT_SECRET }} ZY_ZHIKU_TOKEN_TTL=86400 ZY_COS_SECRET_ID=${{ secrets.ZY_OSS_KEY }} ZY_COS_SECRET_KEY=${{ secrets.ZY_OSS_SECRET }} ZY_COS_BUCKET=${{ secrets.ZY_NOVEL_COS_BUCKET }} ZY_COS_REGION=ap-singapore ZY_ZHIKU_DATA_DIR=/opt/zhiku/data ZY_ZHIKU_LOG_DIR=/var/log/zhiku ZY_ZHIKU_DOMAIN=${{ secrets.ZY_ZHIKU_DOMAIN }} ZY_FANQIE_API_URL=http://127.0.0.1:9999 ZY_QIMAO_API_URL=http://127.0.0.1:7700 ZY_SMTP_PORT=465 ZY_SMTP_USER=${{ secrets.ZY_SMTP_USER }} ZY_SMTP_PASS=${{ secrets.ZY_SMTP_PASS }} ZY_DEEPSEEK_API_URL=https://api.deepseek.com/v1/chat/completions ZY_DEEPSEEK_API_KEY=${{ secrets.ZY_DEEPSEEK_API_KEY }} ENVEOF # ๅŽป้™คๅฏ่ƒฝ็š„ๅ‰ๅฏผ็ฉบๆ ผ sed -i 's/^[[:space:]]*//' /opt/zhiku/server/.env # โ”€โ”€โ”€ ๅฎ‰่ฃ… Node.js ไพ่ต– โ”€โ”€โ”€ cd /opt/zhiku/server npm install --production 2>&1 | tail -5 # โ”€โ”€โ”€ Nginx ้…็ฝฎ โ”€โ”€โ”€ ln -sf /etc/nginx/sites-available/zhiku /etc/nginx/sites-enabled/zhiku # โ”€โ”€โ”€ ๅฏๅŠจๆœๅŠก โ”€โ”€โ”€ cd /opt/zhiku pm2 start ecosystem.config.js pm2 save # โ”€โ”€โ”€ ๅฎ‰่ฃ… COS CLI ๅทฅๅ…ท โ”€โ”€โ”€ if ! command -v coscli &>/dev/null; then wget https://github.com/tencentyun/coscli/releases/download/v0.11.0-beta/coscli-linux chmod +x coscli-linux mv coscli-linux /usr/local/bin/coscli fi # โ”€โ”€โ”€ ้…็ฝฎ COS CLI โ”€โ”€โ”€ mkdir -p ~/.cos.yaml cat > ~/.cos.yaml << 'COSEOF' configs: default: secretid: $ZY_COS_SECRET_ID secretkey: $ZY_COS_SECRET_KEY region: $ZY_COS_REGION bucket: $ZY_COS_BUCKET COSEOF # โ”€โ”€โ”€ ไธŠไผ ๅค‡ไปฝ่„šๆœฌ โ”€โ”€โ”€ mkdir -p /opt/zhiku/scripts # โ”€โ”€โ”€ ่ฎพ็ฝฎๅฎšๆ—ถๅค‡ไปฝไปปๅŠก โ”€โ”€โ”€ (crontab -l 2>/dev/null; echo "0 4 * * * /opt/zhiku/scripts/backup-data-to-cos.sh >> /var/log/zhiku/backup.log 2>&1") | crontab - # โ”€โ”€โ”€ ้‡ๅฏ cron ๆœๅŠก โ”€โ”€โ”€ systemctl restart cron echo "[ZY-SVR-006] ๆœๅŠกๅฏๅŠจๅฎŒๆˆ" ENDSSH - name: '๐Ÿ“ค ไธŠไผ ๅค‡ไปฝ่„šๆœฌ' run: | scp -i ~/.ssh/zhiku_key -o StrictHostKeyChecking=no \ server/zhiku-node/scripts/backup-data-to-cos.sh \ ${{ secrets.ZY_NOVEL_USER }}@${{ secrets.ZY_NOVEL_HOST }}:/opt/zhiku/scripts/ ssh -i ~/.ssh/zhiku_key -o StrictHostKeyChecking=no \ ${{ secrets.ZY_NOVEL_USER }}@${{ secrets.ZY_NOVEL_HOST }} \ 'chmod +x /opt/zhiku/scripts/backup-data-to-cos.sh' - name: 'โœ… ้ชŒ่ฏๆœๅŠก็Šถๆ€' run: | ssh -i ~/.ssh/zhiku_key -o StrictHostKeyChecking=no \ ${{ secrets.ZY_NOVEL_USER }}@${{ secrets.ZY_NOVEL_HOST }} << 'ENDSSH' set -e # ๆฃ€ๆŸฅ PM2 ็Šถๆ€ if ! pm2 list | grep -q "online"; then echo "[ERROR] PM2 ๆœๅŠกๆœชๆญฃๅธธ่ฟ่กŒ" exit 1 fi # ๆฃ€ๆŸฅ API ๅฅๅบท็Šถๆ€ API_HEALTH=$(curl -s http://localhost:3006/api/health | jq -r '.status') if [ "$API_HEALTH" != "running" ]; then echo "[ERROR] API ๅฅๅบทๆฃ€ๆŸฅๅคฑ่ดฅ: $API_HEALTH" exit 1 fi # ๆฃ€ๆŸฅๅค‡ไปฝ่„šๆœฌ if [ ! -x "/opt/zhiku/scripts/backup-data-to-cos.sh" ]; then echo "[ERROR] ๅค‡ไปฝ่„šๆœฌๆœชๆญฃ็กฎๅฎ‰่ฃ…" exit 1 fi # ๆฃ€ๆŸฅๅฎšๆ—ถไปปๅŠก if ! crontab -l | grep -q "backup-data-to-cos"; then echo "[ERROR] ๅฎšๆ—ถๅค‡ไปฝไปปๅŠกๆœช่ฎพ็ฝฎ" exit 1 fi echo "[ZY-SVR-006] ๆ‰€ๆœ‰ๆœๅŠก้ชŒ่ฏ้€š่ฟ‡" ENDSSH # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• # Job 2: ็”ณ่ฏท SSL ่ฏไนฆ # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• setup-ssl: name: '๐Ÿ”’ ็”ณ่ฏท SSL ่ฏไนฆ ยท guanghu.online' runs-on: ubuntu-latest permissions: contents: read if: github.event_name == 'workflow_dispatch' && github.event.inputs.action == 'setup-ssl' steps: - name: '๐Ÿ“ฅ ๆฃ€ๅ‡บไปฃ็ ' uses: actions/checkout@v4 - name: '๐Ÿ”‘ ้…็ฝฎ SSH' run: | mkdir -p ~/.ssh echo "${{ secrets.ZY_NOVEL_KEY }}" > ~/.ssh/zhiku_key chmod 600 ~/.ssh/zhiku_key ssh-keyscan -H ${{ secrets.ZY_NOVEL_HOST }} >> ~/.ssh/known_hosts - name: '๐Ÿ“ฆ ๅฎ‰่ฃ… certbot' run: | ssh -i ~/.ssh/zhiku_key -o StrictHostKeyChecking=no \ ${{ secrets.ZY_NOVEL_USER }}@${{ secrets.ZY_NOVEL_HOST }} << 'ENDSSH' set -e # ๅฎ‰่ฃ… certbot apt-get update apt-get install -y certbot python3-certbot-nginx # ็”ณ่ฏท่ฏไนฆ (webroot ๆจกๅผ) certbot certonly --webroot -w /var/www/certbot \ -d ${{ secrets.ZY_ZHIKU_DOMAIN }} \ -d www.${{ secrets.ZY_ZHIKU_DOMAIN }} \ --non-interactive \ --agree-tos \ --email ${{ secrets.ZY_SMTP_USER }} \ --expand # ่ฎพ็ฝฎ่‡ชๅŠจ็ปญๆœŸ (crontab -l 2>/dev/null; echo "0 3 * * * certbot renew --quiet --post-hook 'systemctl reload nginx'" ) | crontab - # ้‡ๅฏ Nginx systemctl reload nginx echo "[ZY-SVR-006] SSL ่ฏไนฆ็”ณ่ฏทๅฎŒๆˆ" ENDSSH # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• # Job 3: ๅฅๅบทๆฃ€ๆŸฅ # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• health: name: '๐Ÿฉบ ๅฅๅบทๆฃ€ๆŸฅ ยท guanghu.online' runs-on: ubuntu-latest permissions: contents: read if: github.event_name == 'workflow_dispatch' && github.event.inputs.action == 'health' steps: - name: '๐Ÿ“ฅ ๆฃ€ๅ‡บไปฃ็ ' uses: actions/checkout@v4 - name: '๐Ÿ”‘ ้…็ฝฎ SSH' run: | mkdir -p ~/.ssh echo "${{ secrets.ZY_NOVEL_KEY }}" > ~/.ssh/zhiku_key chmod 600 ~/.ssh/zhiku_key ssh-keyscan -H ${{ secrets.ZY_NOVEL_HOST }} >> ~/.ssh/known_hosts - name: '๐Ÿ”„ ๆฃ€ๆŸฅๆœๅŠก็Šถๆ€' run: | ssh -i ~/.ssh/zhiku_key -o StrictHostKeyChecking=no \ ${{ secrets.ZY_NOVEL_USER }}@${{ secrets.ZY_NOVEL_HOST }} << 'ENDSSH' set -e # ๆฃ€ๆŸฅ PM2 echo "=== PM2 ็Šถๆ€ ===" pm2 list # ๆฃ€ๆŸฅ API ๅฅๅบท echo "\n=== API ๅฅๅบท็Šถๆ€ ===" curl -s http://localhost:3006/api/health | jq # ๆฃ€ๆŸฅ Nginx echo "\n=== Nginx ็Šถๆ€ ===" systemctl status nginx --no-pager # ๆฃ€ๆŸฅๅค‡ไปฝๆ—ฅๅฟ— echo "\n=== ๆœ€่ฟ‘ๅค‡ไปฝๆ—ฅๅฟ— ===" tail -n 20 /var/log/zhiku/backup.log 2>/dev/null || echo "ๆ— ๅค‡ไปฝๆ—ฅๅฟ—" # ๆฃ€ๆŸฅๅฎšๆ—ถไปปๅŠก echo "\n=== ๅฎšๆ—ถไปปๅŠก ===" crontab -l echo "[ZY-SVR-006] ๅฅๅบทๆฃ€ๆŸฅๅฎŒๆˆ" ENDSSH # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• # Job 4: ๅ›žๆปš # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• rollback: name: 'โช ๅ›žๆปšๅˆฐไธŠไธ€็‰ˆๆœฌ ยท guanghu.online' runs-on: ubuntu-latest permissions: contents: read if: github.event_name == 'workflow_dispatch' && github.event.inputs.action == 'rollback' steps: - name: '๐Ÿ“ฅ ๆฃ€ๅ‡บไปฃ็ ' uses: actions/checkout@v4 - name: '๐Ÿ”‘ ้…็ฝฎ SSH' run: | mkdir -p ~/.ssh echo "${{ secrets.ZY_NOVEL_KEY }}" > ~/.ssh/zhiku_key chmod 600 ~/.ssh/zhiku_key ssh-keyscan -H ${{ secrets.ZY_NOVEL_HOST }} >> ~/.ssh/known_hosts - name: 'โช ๆ‰ง่กŒๅ›žๆปš' run: | ssh -i ~/.ssh/zhiku_key -o StrictHostKeyChecking=no \ ${{ secrets.ZY_NOVEL_USER }}@${{ secrets.ZY_NOVEL_HOST }} << 'ENDSSH' set -e # ๅ›žๆปš PM2 cd /opt/zhiku pm2 restart ecosystem.config.js echo "[ZY-SVR-006] ๅ›žๆปšๅฎŒๆˆ" ENDSSH