guanghulab/scripts/server-patrol.sh
2026-05-10 13:12:44 +08:00

190 lines
6.0 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters

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.

#!/bin/bash
# server-patrol.sh · 铸渊每日服务器巡检
# 部署位置:服务器 /var/www/_shared/server-patrol.sh
# 执行方式铸渊SSH到服务器后 bash /var/www/_shared/server-patrol.sh
# 输出JSON格式巡检报告到 /tmp/patrol-report.json
set -uo pipefail
TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%SZ)
REPORT="/tmp/patrol-report.json"
ALERTS=()
FIXED=()
echo "===== 🔍 铸渊服务器巡检 · ${TIMESTAMP} ====="
# ━━━ 检查项1Nginx 运行状态 ━━━
echo "[1/7] Nginx 状态..."
if systemctl is-active --quiet nginx; then
NGINX_STATUS="running"
echo " ✅ Nginx 运行中"
else
NGINX_STATUS="down"
ALERTS+=("Nginx 未运行")
echo " ❌ Nginx 未运行!尝试重启..."
systemctl restart nginx
if systemctl is-active --quiet nginx; then
FIXED+=("Nginx 已自动重启恢复")
NGINX_STATUS="recovered"
echo " ✅ Nginx 已恢复"
else
echo " ❌ Nginx 重启失败!需要人工介入"
fi
fi
# ━━━ 检查项2各沙盒模块冒烟检查 ━━━
echo "[2/7] 模块冒烟检查..."
# 已知已部署的模块URL后续铸渊从 deploy-status.json 动态读取)
URLS=(
"https://guanghulab.com/|主站首页"
"https://guanghulab.com/status-board/|DEV-005·看板"
"https://guanghulab.com/cost-control/|DEV-005·成本控制"
)
for entry in "${URLS[@]}"; do
IFS='|' read -r url name <<< "$entry"
STATUS=$(curl -o /dev/null -s -w "%{http_code}" --max-time 10 "$url")
if [ "$STATUS" = "200" ]; then
echo "${name}${STATUS}"
else
echo "${name}${STATUS}"
ALERTS+=("${name} 返回 ${STATUS}")
fi
done
# ━━━ 检查项3PM2 进程状态 ━━━
echo "[3/7] PM2 进程..."
if command -v pm2 &> /dev/null; then
PM2_STATUS=$(pm2 jlist 2>/dev/null)
PM2_STOPPED=$(echo "$PM2_STATUS" | python3 -c "
import sys, json
try:
procs = json.load(sys.stdin)
stopped = [p['name'] for p in procs if p.get('pm2_env',{}).get('status') != 'online']
print(','.join(stopped) if stopped else 'none')
except:
print('parse_error')" 2>/dev/null)
if [ "$PM2_STOPPED" = "none" ]; then
echo " ✅ 所有PM2进程正常"
elif [ "$PM2_STOPPED" = "parse_error" ]; then
echo " ⚠️ PM2状态解析失败"
ALERTS+=("PM2状态解析失败")
else
echo " ❌ 以下进程异常: ${PM2_STOPPED}"
ALERTS+=("PM2进程异常: ${PM2_STOPPED}")
# 尝试重启
IFS=',' read -ra PROCS <<< "$PM2_STOPPED"
for proc in "${PROCS[@]}"; do
pm2 restart "$proc" 2>/dev/null
if pm2 show "$proc" 2>/dev/null | grep -q "online"; then
FIXED+=("PM2进程 ${proc} 已自动重启")
echo "${proc} 已重启恢复"
else
echo "${proc} 重启失败"
fi
done
fi
else
echo " ⚠️ PM2 未安装"
fi
# ━━━ 检查项4磁盘空间 ━━━
echo "[4/7] 磁盘空间..."
DISK_USAGE=$(df -h / | awk 'NR==2 {print $5}' | tr -d '%')
if [ "$DISK_USAGE" -gt 90 ]; then
echo " ❌ 磁盘使用率 ${DISK_USAGE}%超过90%警戒线)"
ALERTS+=("磁盘使用率 ${DISK_USAGE}%")
elif [ "$DISK_USAGE" -gt 80 ]; then
echo " ⚠️ 磁盘使用率 ${DISK_USAGE}%(接近警戒线)"
else
echo " ✅ 磁盘使用率 ${DISK_USAGE}%"
fi
# ━━━ 检查项5沙盒目录权限 ━━━
echo "[5/7] 沙盒目录权限..."
for DEV_ID in DEV-001 DEV-002 DEV-003 DEV-004 DEV-005 DEV-009 DEV-010 DEV-011 DEV-012 DEV-013 DEV-014; do
SANDBOX="/var/www/${DEV_ID}"
if [ -d "$SANDBOX" ]; then
OWNER=$(stat -c '%U:%G' "$SANDBOX")
PERM=$(stat -c '%a' "$SANDBOX")
if [ "$OWNER" != "nginx:nginx" ] || [ "$PERM" != "755" ]; then
echo "${DEV_ID}: owner=${OWNER} perm=${PERM}(应为 nginx:nginx 755"
ALERTS+=("${DEV_ID} 权限异常: ${OWNER} ${PERM}")
# 自动修复
chown nginx:nginx "$SANDBOX"
chmod 755 "$SANDBOX"
FIXED+=("${DEV_ID} 权限已自动修复")
echo "${DEV_ID} 权限已修复"
fi
fi
done
echo " ✅ 沙盒权限检查完成"
# ━━━ 检查项6SSL证书有效期 ━━━
echo "[6/7] SSL证书..."
SSL_EXPIRY=$(echo | openssl s_client -servername guanghulab.com -connect guanghulab.com:443 2>/dev/null | openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2)
if [ -n "$SSL_EXPIRY" ]; then
EXPIRY_EPOCH=$(date -d "$SSL_EXPIRY" +%s 2>/dev/null)
NOW_EPOCH=$(date +%s)
DAYS_LEFT=$(( (EXPIRY_EPOCH - NOW_EPOCH) / 86400 ))
if [ "$DAYS_LEFT" -lt 7 ]; then
echo " ❌ SSL证书将在 ${DAYS_LEFT} 天后过期!"
ALERTS+=("SSL证书 ${DAYS_LEFT} 天后过期")
elif [ "$DAYS_LEFT" -lt 30 ]; then
echo " ⚠️ SSL证书还有 ${DAYS_LEFT} 天过期"
else
echo " ✅ SSL证书还有 ${DAYS_LEFT}"
fi
else
echo " ⚠️ 无法获取SSL证书信息"
fi
# ━━━ 检查项7Nginx配置语法 ━━━
echo "[7/7] Nginx配置语法..."
NGINX_TEST=$(nginx -t 2>&1)
if echo "$NGINX_TEST" | grep -q "successful"; then
echo " ✅ Nginx配置语法正确"
else
echo " ❌ Nginx配置有语法错误"
ALERTS+=("Nginx配置语法错误")
fi
# ━━━ 生成JSON报告 ━━━
ALERT_COUNT=${#ALERTS[@]}
FIXED_COUNT=${#FIXED[@]}
ALERT_JSON="[]"
if [ $ALERT_COUNT -gt 0 ]; then
ALERT_JSON=$(printf '%s\n' "${ALERTS[@]}" | python3 -c "import sys,json; print(json.dumps([l.strip() for l in sys.stdin]))")
fi
FIXED_JSON="[]"
if [ $FIXED_COUNT -gt 0 ]; then
FIXED_JSON=$(printf '%s\n' "${FIXED[@]}" | python3 -c "import sys,json; print(json.dumps([l.strip() for l in sys.stdin]))")
fi
cat > "$REPORT" << EOF
{
"timestamp": "${TIMESTAMP}",
"nginx_status": "${NGINX_STATUS}",
"disk_usage_percent": ${DISK_USAGE},
"alert_count": ${ALERT_COUNT},
"fixed_count": ${FIXED_COUNT},
"alerts": ${ALERT_JSON},
"auto_fixed": ${FIXED_JSON},
"overall": "$([ $ALERT_COUNT -eq 0 ] && echo 'healthy' || echo 'has_issues')"
}
EOF
echo ""
echo "===== 📊 巡检结果 ====="
if [ $ALERT_COUNT -eq 0 ]; then
echo "✅ 全部正常 · 无异常"
else
echo "⚠️ 发现 ${ALERT_COUNT} 个异常 · 自动修复 ${FIXED_COUNT}"
fi
echo "报告已保存到 ${REPORT}"
cat "$REPORT"