mirror of
https://gitee.com/xmz7891/ykxmz.git
synced 2026-10-18 13:40:45 +00:00
监测单元和预案重写成"分层"版(来源改为本地整份文件)
== 为什么重写 ==
certbot 签证书时加了 http -> https 的 301,而监测单元原来判断
"curl 拿到 200 才算健康"、且 curl **默认不跟跳转** -> 拿到 301
-> 判成"网站挂了" -> 又要启动预案 -> 重启中转 -> 再查还是 301。
这是**第二次**踩同一类坑了(上一次是改监听地址忘了改探测地址)。
共同教训:**改了入口的行为,必须回头看所有探测入口的地方。**
== 新设计:分两层探测 ==
PRIMARY https://yk.xxmxxs.top/v1/health 用户实际走的路
FALLBACK http://127.0.0.1:13245/v1/health 中转本身
两个都查才能分清哪一层坏了,进而选对抢救动作:
PRIMARY 挂 + FALLBACK 好 -> edge 层(CF / DNS / nginx)
两个都挂 -> core 层(中转服务本身)
预案据此走不同的阶梯:
edge: 重载 nginx -> 重启 nginx -> 查 443 与证书
core: 重启中转 -> 强杀重拉 -> 中转+nginx 都重启
不区分层次的话只能瞎重启,而 edge 层的问题重启中转一万次也没用。
== 做法上的改进:不再远端打补丁 ==
前几轮一直是"SSH 过去用嵌套 heredoc 现场改 monitor.sh",
连续踩三次:PowerShell 在本机求值 \、引号被吃、
脚本里的 %{http_code} 和 Python 的 %% 格式化打架。
现在改成:relay/monitor-lightsail.sh 和 relay/rescue-lightsail.sh
是**唯一事实来源**,本地编辑 -> 整份上传 -> 重装,
改了什么一目了然,也能进 git。
== 顺带 ==
因为 Lightsail 防火墙还没放行 443,PRIMARY 一直是 000,
监测会把 fails 一直加上去、白生成抢救报告。
所以暂时把 monitor.timer 停掉,等 443 开了再启用
(脚本 _build/pause_monitor.py,恢复是一条 systemctl start)。
This commit is contained in:
+200
-106
@@ -3,40 +3,54 @@
|
||||
# 紧急预案(Lightsail 版)—— 网站打不开时按阶梯自动抢救
|
||||
# ============================================================================
|
||||
#
|
||||
# 和随身 WiFi 那版的区别:
|
||||
# ── 和旧那版的区别 ────────────────────────────────────────────────────
|
||||
#
|
||||
# 那版是**围着 Cloudflare 隧道**转的(第 1 级就是重启隧道、
|
||||
# 第 3 级重施 MSS/MTU 调优)。现在这台新机器**有公网 IP**,
|
||||
# 中转直接对外监听 13245,没有任何隧道 —— 所以:
|
||||
# 旧机器是围着 Cloudflare 隧道转的(第 1 级重启隧道、第 3 级重施
|
||||
# MSS/MTU 调优)。新机器**有公网 IP、没有隧道**,中转跑在 nginx 后面,
|
||||
# 所以阶梯完全重写。
|
||||
#
|
||||
# * 第 1 级从"重启隧道"改成"重启中转服务"
|
||||
# * 去掉 MSS/MTU 那两级(那是 4G 线路的问题,这里没有)
|
||||
# * 加一级"看端口有没有被占/进程死没死"
|
||||
# ── 核心改进:先看是哪一层坏的 ────────────────────────────────────────
|
||||
#
|
||||
# 保留下来的核心设计没变:
|
||||
# 监测单元会传进来层次:
|
||||
#
|
||||
# edge = 中转本身是好的(127.0.0.1:13245 返回 200),
|
||||
# 但用户走的路(Cloudflare -> nginx)不通
|
||||
# -> 该动 nginx / 查 DNS / 查 Cloudflare
|
||||
# -> **重启中转服务毫无用处**
|
||||
#
|
||||
# core = 中转本身也不通
|
||||
# -> 该重启中转
|
||||
#
|
||||
# 不区分层次的话就只能瞎重启 —— 而 edge 层的问题重启中转一万次也没用,
|
||||
# 只会把报告淹掉。
|
||||
#
|
||||
# ── 保留的核心设计 ────────────────────────────────────────────────────
|
||||
#
|
||||
# 1. **先记录现场,再动手**(重启会把证据冲掉)
|
||||
# 2. **阶梯式,每级都验**:从代价最小到最大,好了就停
|
||||
# 3. **全失败要留证据**:生成 txt 报告,后台可下载
|
||||
# 2. **阶梯式,每级都验**:代价从最小到最大,好了就停
|
||||
# 3. **全失败要留证据**:生成 txt 报告,可下载
|
||||
# 4. **成功的招数记进知识库**:下次同类问题优先试
|
||||
#
|
||||
# 谁调用:monitor.sh(连续 N 次不通就调这里)
|
||||
# 也可以人工跑:bash /opt/ykxmz-relay/rescue.sh
|
||||
# 谁调用:monitor.sh
|
||||
# 也可以人工跑:bash /opt/ykxmz-relay/rescue.sh "手工测试"
|
||||
# ============================================================================
|
||||
|
||||
set -u
|
||||
|
||||
RELAY_DIR="${RELAY_DIR:-/opt/ykxmz-relay}"
|
||||
DOMAIN="${DOMAIN:-yk.xxmxxs.top}"
|
||||
PORT="${RELAY_PORT:-13245}"
|
||||
# 公网健康检查地址。没有域名就填 IP。
|
||||
PUBLIC_URL="${PUBLIC_URL:-http://13.54.30.196:$PORT}"
|
||||
|
||||
PRIMARY_URL="${PRIMARY_URL:-https://$DOMAIN}"
|
||||
FALLBACK_URL="${FALLBACK_URL:-http://127.0.0.1:$PORT}"
|
||||
|
||||
REPORTS_DIR="$RELAY_DIR/rescue_reports"
|
||||
KNOWLEDGE="$RELAY_DIR/rescue_knowledge.md"
|
||||
LOG="$RELAY_DIR/rescue.log"
|
||||
LOCKFILE="/tmp/ykxmz-rescue.lock"
|
||||
|
||||
SETTLE_FAST=6
|
||||
SETTLE_SLOW=15
|
||||
SETTLE_SLOW=12
|
||||
|
||||
# 是否允许"重启整机"这张底牌。默认关。
|
||||
RESCUE_REBOOT="${RESCUE_REBOOT:-0}"
|
||||
@@ -57,24 +71,34 @@ say() {
|
||||
echo "$(date '+%F %T') $*" >> "$LOG"
|
||||
}
|
||||
|
||||
# 公网健康检查 —— **看公网,不看本机**
|
||||
# 用户那层通了才算网站是好的
|
||||
is_healthy() {
|
||||
local code
|
||||
code=$(curl -s -o /dev/null -w '%{http_code}' --max-time 12 \
|
||||
"$PUBLIC_URL/v1/health" 2>/dev/null)
|
||||
code=$(curl -sL -o /dev/null -w '%{http_code}' --max-time 12 \
|
||||
"$PRIMARY_URL/v1/health" 2>/dev/null)
|
||||
[ "$code" = "200" ]
|
||||
}
|
||||
|
||||
local_health() {
|
||||
# 中转本身
|
||||
core_ok() {
|
||||
local code
|
||||
code=$(curl -s -o /dev/null -w '%{http_code}' --max-time 6 \
|
||||
"http://127.0.0.1:$PORT/v1/health" 2>/dev/null)
|
||||
"$FALLBACK_URL/v1/health" 2>/dev/null)
|
||||
[ "$code" = "200" ]
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# nginx 本机(带 SNI 走 443)
|
||||
nginx_ok() {
|
||||
local code
|
||||
code=$(curl -sk -o /dev/null -w '%{http_code}' --max-time 8 \
|
||||
--resolve "$DOMAIN:443:127.0.0.1" \
|
||||
"https://$DOMAIN/v1/health" 2>/dev/null)
|
||||
[ "$code" = "200" ]
|
||||
}
|
||||
|
||||
# ===========================================================================
|
||||
# 现场记录
|
||||
# ---------------------------------------------------------------------------
|
||||
# ===========================================================================
|
||||
collect() {
|
||||
{
|
||||
echo "================================================================================"
|
||||
@@ -82,74 +106,95 @@ collect() {
|
||||
echo " 时间:$(date '+%F %T %Z')"
|
||||
echo " 主机:$(hostname) 运行时长:$(uptime -p 2>/dev/null || uptime)"
|
||||
echo " 触发原因:$1"
|
||||
echo " 层次判断:${LAYER:-未知}"
|
||||
echo "================================================================================"
|
||||
echo
|
||||
echo "---- 一、结论速览 ----"
|
||||
echo
|
||||
echo " 公网 $PUBLIC_URL/v1/health -> $(is_healthy && echo 200-正常 || echo 不通)"
|
||||
echo " 本机 http://127.0.0.1:$PORT/v1/health -> $(local_health && echo 200-正常 || echo 不通)"
|
||||
echo " 用户层 $PRIMARY_URL/v1/health -> $(is_healthy && echo '200 正常' || echo 不通)"
|
||||
echo " 中转层 $FALLBACK_URL/v1/health -> $(core_ok && echo '200 正常' || echo 不通)"
|
||||
echo " nginx https://$DOMAIN (本机带 SNI) -> $(nginx_ok && echo '200 正常' || echo 不通)"
|
||||
echo
|
||||
if local_health && ! is_healthy; then
|
||||
echo " 判断:**本机是好的,问题在公网那一侧**(防火墙规则、安全组、上游线路)。"
|
||||
elif ! local_health; then
|
||||
echo " 判断:**本机的中转服务就没起来**,先看第二、三节。"
|
||||
else
|
||||
echo " 判断:两边都通(可能是刚才已经自愈,或者只是偶发抖动)。"
|
||||
fi
|
||||
case "${LAYER:-}" in
|
||||
edge)
|
||||
echo " 判断:**中转是好的,问题在边缘层**(Cloudflare / DNS / nginx)。"
|
||||
echo " 要动的是 nginx,不是中转。"
|
||||
echo " 常见原因:"
|
||||
echo " * Lightsail 防火墙没开 443(Cloudflare Full 模式回源要用)"
|
||||
echo " * Cloudflare 的 SSL/TLS 模式和源站对不上"
|
||||
echo " * DNS 记录被改成了灰色云朵,或者指向了别的 IP"
|
||||
;;
|
||||
core)
|
||||
echo " 判断:**中转服务本身不通**,先看第二、三节。"
|
||||
;;
|
||||
*)
|
||||
echo " 判断:两层都通(可能已自愈),或者只是偶发抖动。"
|
||||
;;
|
||||
esac
|
||||
echo
|
||||
echo "---- 二、服务状态 ----"
|
||||
echo
|
||||
printf ' %-24s %s\n' "ykxmz-relay" "$(systemctl is-active ykxmz-relay 2>&1)"
|
||||
printf ' %-24s %s\n' "ykxmz-monitor.timer" "$(systemctl is-active ykxmz-monitor.timer 2>&1)"
|
||||
for s in ykxmz-relay nginx ykxmz-monitor.timer certbot.timer; do
|
||||
printf ' %-24s %s\n' "$s" "$(systemctl is-active $s 2>&1)"
|
||||
done
|
||||
echo
|
||||
echo " --- 最近 20 行服务日志 ---"
|
||||
journalctl -u ykxmz-relay --no-pager -n 20 2>/dev/null | sed 's/^/ /'
|
||||
echo " --- 中转最近 15 行日志 ---"
|
||||
journalctl -u ykxmz-relay --no-pager -n 15 2>/dev/null | sed 's/^/ /'
|
||||
echo
|
||||
echo " --- nginx 最近 15 行错误日志 ---"
|
||||
tail -15 /var/log/nginx/ykxmz-error.log 2>/dev/null | sed 's/^/ /'
|
||||
echo
|
||||
echo "---- 三、进程与端口 ----"
|
||||
echo
|
||||
echo " 监听 $PORT 的进程:"
|
||||
ss -tlnp 2>/dev/null | grep ":$PORT " | sed 's/^/ /' \
|
||||
|| echo " **没有任何进程在监听 $PORT**"
|
||||
echo " 监听情况:"
|
||||
ss -tlnp 2>/dev/null | grep -E ':(80|443|'"$PORT"') ' | sed 's/^/ /'
|
||||
echo
|
||||
echo " 相关进程:"
|
||||
ps -eo pid,rss,etime,cmd --sort=-rss 2>/dev/null \
|
||||
| grep -E 'relay\.py|python3' | grep -v grep | head -6 | sed 's/^/ /'
|
||||
| grep -E 'relay\.py|nginx' | grep -v grep | head -6 | sed 's/^/ /'
|
||||
echo
|
||||
echo "---- 四、系统资源 ----"
|
||||
echo "---- 四、本机各层自测 ----"
|
||||
echo
|
||||
printf ' %-34s %s\n' "中转 127.0.0.1:$PORT" \
|
||||
"$(curl -s -o /dev/null -w '%{http_code}' --max-time 6 http://127.0.0.1:$PORT/v1/health)"
|
||||
printf ' %-34s %s\n' "nginx :80(应 301)" \
|
||||
"$(curl -s -o /dev/null -w '%{http_code}' --max-time 6 http://127.0.0.1:80/v1/health)"
|
||||
printf ' %-34s %s\n' "nginx :443(带 SNI)" \
|
||||
"$(curl -sk -o /dev/null -w '%{http_code}' --max-time 8 --resolve "$DOMAIN:443:127.0.0.1" https://$DOMAIN/v1/health)"
|
||||
printf ' %-34s %s\n' "用户层 $PRIMARY_URL" \
|
||||
"$(curl -sL -o /dev/null -w '%{http_code}' --max-time 12 $PRIMARY_URL/v1/health)"
|
||||
echo
|
||||
echo "---- 五、证书 ----"
|
||||
echo
|
||||
certbot certificates 2>/dev/null | grep -E 'Certificate Name|Domains|Expiry' \
|
||||
| sed 's/^/ /'
|
||||
echo
|
||||
echo "---- 六、系统资源 ----"
|
||||
echo
|
||||
free -m 2>/dev/null | sed 's/^/ /'
|
||||
echo
|
||||
uptime | sed 's/^/ /'
|
||||
echo
|
||||
df -h / /opt 2>/dev/null | sed 's/^/ /'
|
||||
df -h / 2>/dev/null | sed 's/^/ /'
|
||||
echo
|
||||
echo "---- 五、网络 ----"
|
||||
echo "---- 七、网络 ----"
|
||||
echo
|
||||
ip -brief addr show 2>/dev/null | sed 's/^/ /'
|
||||
echo
|
||||
echo " 默认路由:"
|
||||
ip route show default 2>/dev/null | sed 's/^/ /'
|
||||
echo
|
||||
echo " 本机自测各端口:"
|
||||
for p in "$PORT" 80 443 22; do
|
||||
printf ' %-6s ' "$p"
|
||||
timeout 3 bash -c "</dev/tcp/127.0.0.1/$p" 2>/dev/null \
|
||||
&& echo "通" || echo "不通"
|
||||
done
|
||||
echo " 公网 IP:$(curl -s --max-time 8 https://api.ipify.org 2>/dev/null || echo 取不到)"
|
||||
echo
|
||||
echo "---- 六、日志尾部 ----"
|
||||
echo " DNS 解析 $DOMAIN:"
|
||||
getent hosts "$DOMAIN" 2>/dev/null | sed 's/^/ /' || echo " 解析失败"
|
||||
echo
|
||||
echo "### 中转服务 relay.log"
|
||||
tail -30 "$RELAY_DIR/relay.log" 2>/dev/null | sed 's/^/ /'
|
||||
echo "---- 八、内核异常(OOM / 硬件)----"
|
||||
echo
|
||||
echo "### 监测单元 monitor.log"
|
||||
tail -20 "$RELAY_DIR/monitor.log" 2>/dev/null | sed 's/^/ /'
|
||||
dmesg -T 2>/dev/null | grep -i -E 'oom|killed process|panic' \
|
||||
| tail -10 | sed 's/^/ /'
|
||||
echo
|
||||
echo "### 内核异常(OOM / 硬件)"
|
||||
dmesg -T 2>/dev/null \
|
||||
| grep -i -E 'oom|killed process|error|panic' | tail -15 | sed 's/^/ /'
|
||||
echo
|
||||
echo "---- 七、最近一次启动 ----"
|
||||
echo "---- 九、最近一次启动 ----"
|
||||
echo
|
||||
who -b 2>/dev/null | sed 's/^/ /'
|
||||
echo " 运行时长:$(cut -d. -f1 /proc/uptime 2>/dev/null) 秒"
|
||||
@@ -161,53 +206,73 @@ collect() {
|
||||
say " 现场已记录 -> $REPORT"
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 阶梯
|
||||
# ---------------------------------------------------------------------------
|
||||
# ===========================================================================
|
||||
# 阶梯 —— 按层次走
|
||||
# ===========================================================================
|
||||
|
||||
step_1_restart_relay() {
|
||||
say " [1/4] 重启中转服务(最轻的一招,不动系统其他部分)"
|
||||
systemctl restart ykxmz-relay 2>/dev/null
|
||||
step_edge_1_reload_nginx() {
|
||||
say " [edge-1] 重载 nginx 配置(最轻,不断连接)"
|
||||
sudo nginx -t >/dev/null 2>&1 && sudo systemctl reload nginx 2>/dev/null
|
||||
sleep "$SETTLE_FAST"
|
||||
}
|
||||
|
||||
step_2_kill_and_start() {
|
||||
say " [2/4] 强杀残留进程再拉起(进程卡死/端口被占时用)"
|
||||
# 有时候 systemd restart 会因为老进程没退干净而失败,
|
||||
# 表现为"服务说 active 但端口没人听"。
|
||||
pkill -f "$RELAY_DIR/relay.py" 2>/dev/null
|
||||
sleep 3
|
||||
systemctl reset-failed ykxmz-relay 2>/dev/null
|
||||
systemctl start ykxmz-relay 2>/dev/null
|
||||
step_edge_2_restart_nginx() {
|
||||
say " [edge-2] 重启 nginx(重载不够时用)"
|
||||
sudo systemctl restart nginx 2>/dev/null
|
||||
sleep "$SETTLE_FAST"
|
||||
}
|
||||
|
||||
step_3_check_firewall() {
|
||||
say " [3/4] 检查本机防火墙有没有挡住 $PORT"
|
||||
# Lightsail 有两层:网页上的防火墙规则(实例级)+ 系统内的 ufw/iptables。
|
||||
# 网页那层我们改不了,但系统内这层能看。
|
||||
if command -v ufw >/dev/null 2>&1; then
|
||||
echo " ufw 状态:$(ufw status 2>/dev/null | head -1)" >> "$LOG"
|
||||
ufw status 2>/dev/null | grep -q "$PORT" \
|
||||
|| say " ⚠ ufw 里没有放行 $PORT 的规则"
|
||||
step_edge_3_check_443() {
|
||||
say " [edge-3] 查公网 443 通不通(Cloudflare Full 模式回源要用)"
|
||||
if timeout 5 bash -c "</dev/tcp/$(curl -s --max-time 6 https://api.ipify.org 2>/dev/null)/443" 2>/dev/null; then
|
||||
say " 本机自连 443 通"
|
||||
else
|
||||
say " ⚠ 本机自连 443 **不通** —— nginx 可能没在 443 上"
|
||||
ss -tln 2>/dev/null | grep ':443 ' | sed 's/^/ /'
|
||||
fi
|
||||
local n
|
||||
n=$(iptables -L INPUT -n 2>/dev/null | grep -c "$PORT")
|
||||
say " iptables INPUT 里提到 $PORT 的规则:$n 条"
|
||||
# 重新绑一次端口(有时是监听 socket 坏了)
|
||||
systemctl restart ykxmz-relay 2>/dev/null
|
||||
say " ⚠ 提醒:**Lightsail 网页上的防火墙规则**系统内部改不了。"
|
||||
say " 如果这里一切正常但公网还是不通,去网页上确认 443 已放行。"
|
||||
# 顺手确认证书还在
|
||||
if [ -f "/etc/letsencrypt/live/$DOMAIN/fullchain.pem" ]; then
|
||||
say " 证书存在,到期日:$(openssl x509 -in "/etc/letsencrypt/live/$DOMAIN/fullchain.pem" -noout -enddate 2>/dev/null | cut -d= -f2)"
|
||||
else
|
||||
say " ⚠ **找不到证书**!/etc/letsencrypt/live/$DOMAIN/fullchain.pem"
|
||||
fi
|
||||
sleep "$SETTLE_SLOW"
|
||||
}
|
||||
|
||||
step_core_1_restart_relay() {
|
||||
say " [core-1] 重启中转服务"
|
||||
sudo systemctl restart ykxmz-relay 2>/dev/null
|
||||
sleep "$SETTLE_FAST"
|
||||
}
|
||||
|
||||
step_core_2_kill_and_start() {
|
||||
say " [core-2] 强杀残留进程再拉起(进程卡死/端口被占时用)"
|
||||
sudo pkill -f "$RELAY_DIR/relay.py" 2>/dev/null
|
||||
sleep 3
|
||||
sudo systemctl reset-failed ykxmz-relay 2>/dev/null
|
||||
sudo systemctl start ykxmz-relay 2>/dev/null
|
||||
sleep "$SETTLE_FAST"
|
||||
}
|
||||
|
||||
step_core_3_restart_all() {
|
||||
say " [core-3] 中转 + nginx 都重启一遍"
|
||||
sudo systemctl restart ykxmz-relay 2>/dev/null
|
||||
sleep 2
|
||||
sudo systemctl restart nginx 2>/dev/null
|
||||
sleep "$SETTLE_SLOW"
|
||||
}
|
||||
|
||||
step_4_reboot() {
|
||||
if [ "$RESCUE_REBOOT" != "1" ]; then
|
||||
say " [4/4] 重启整机 —— **已跳过**(默认不开)"
|
||||
say " 要允许自动重启,把 RESCUE_REBOOT=1 写进 ykxmz-monitor.service。"
|
||||
say " [4] 重启整机 —— **已跳过**(默认不开)"
|
||||
say " 要允许自动重启,把 RESCUE_REBOOT=1 写进 ykxmz-monitor.service。"
|
||||
return 1
|
||||
fi
|
||||
say " [4/4] 重启整机(最后的底牌)"
|
||||
say " [4] 重启整机(最后的底牌)"
|
||||
sync
|
||||
systemctl reboot 2>/dev/null
|
||||
sudo systemctl reboot 2>/dev/null
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -218,8 +283,9 @@ remember() {
|
||||
echo "## $(date '+%F %T') 第 $step 级奏效"
|
||||
echo
|
||||
echo "- 症状:$reason"
|
||||
echo "- 层次:${LAYER:-未知}"
|
||||
echo "- 有效步骤:$step"
|
||||
echo "- 当时公网:$(is_healthy && echo 通 || echo 不通);本机:$(local_health && echo 通 || echo 不通)"
|
||||
echo "- 当时用户层:$(is_healthy && echo 通 || echo 不通);中转层:$(core_ok && echo 通 || echo 不通)"
|
||||
echo "- 详情见 rescue_reports/$(basename "$REPORT")"
|
||||
} >> "$KNOWLEDGE"
|
||||
say " 已把「第 $step 级奏效」记进 $KNOWLEDGE"
|
||||
@@ -231,49 +297,77 @@ remember() {
|
||||
|
||||
REASON="${1:-monitor 触发}"
|
||||
|
||||
# 从触发原因里认出层次(monitor.sh 会传"层次 edge"这样的字样)
|
||||
LAYER=""
|
||||
case "$REASON" in
|
||||
*"层次 edge"*) LAYER="edge" ;;
|
||||
*"层次 core"*) LAYER="core" ;;
|
||||
esac
|
||||
# 认不出来就自己判
|
||||
if [ -z "$LAYER" ]; then
|
||||
if ! core_ok; then LAYER="core"
|
||||
elif ! is_healthy; then LAYER="edge"
|
||||
fi
|
||||
fi
|
||||
|
||||
say ""
|
||||
say "================================================================================"
|
||||
say " 紧急预案启动:$REASON"
|
||||
say " 层次判断:${LAYER:-两层都通}"
|
||||
say "================================================================================"
|
||||
|
||||
# ⚠ 先复查再记录现场。
|
||||
# collect() 会写一份报告文件;如果网站其实已经好了,
|
||||
# 那一次也会留下报告,把真正出事时的报告淹掉(后台只显示最近 30 份)。
|
||||
if is_healthy; then
|
||||
say " 复查:公网现在是通的,不需要动手 —— 不采现场、不留报告。"
|
||||
say " 复查:用户层现在是通的,不需要动手 —— 不采现场、不留报告。"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
collect "$REASON"
|
||||
|
||||
STEP_NAMES=("重启中转服务" "强杀残留再拉起" "查防火墙并重绑" "重启整机")
|
||||
if [ "$LAYER" = "edge" ]; then
|
||||
STEPS=("重载 nginx" "重启 nginx" "查 443 与证书")
|
||||
FUNCS=(step_edge_1_reload_nginx step_edge_2_restart_nginx step_edge_3_check_443)
|
||||
else
|
||||
STEPS=("重启中转服务" "强杀残留再拉起" "中转+nginx 都重启")
|
||||
FUNCS=(step_core_1_restart_relay step_core_2_kill_and_start step_core_3_restart_all)
|
||||
fi
|
||||
|
||||
for i in 1 2 3 4; do
|
||||
case $i in
|
||||
1) step_1_restart_relay ;;
|
||||
2) step_2_kill_and_start ;;
|
||||
3) step_3_check_firewall ;;
|
||||
4) step_4_reboot || continue ;;
|
||||
esac
|
||||
for i in 0 1 2; do
|
||||
${FUNCS[$i]}
|
||||
|
||||
if is_healthy; then
|
||||
say ""
|
||||
say " ✅ 第 $i 级(${STEP_NAMES[$((i-1))]})救回来了,公网已恢复。"
|
||||
remember "$i" "$REASON"
|
||||
say " ✅ 第 $((i+1)) 级(${STEPS[$i]})救回来了,用户层已恢复。"
|
||||
remember "$((i+1))" "$REASON"
|
||||
exit 0
|
||||
fi
|
||||
say " 第 $i 级没解决,继续下一级"
|
||||
say " 第 $((i+1)) 级没解决,继续下一级"
|
||||
done
|
||||
|
||||
# 兜底:把两边都试一遍(有时候层次判错了)
|
||||
say ""
|
||||
say " ❌ 四级都没解决。再采一次现场(状态已经变了)"
|
||||
collect "$REASON(四级抢救后仍不通)"
|
||||
say " 三轮都没解决,兜底:中转和 nginx 各重启一次"
|
||||
sudo systemctl restart ykxmz-relay 2>/dev/null
|
||||
sleep 3
|
||||
sudo systemctl restart nginx 2>/dev/null
|
||||
sleep "$SETTLE_SLOW"
|
||||
if is_healthy; then
|
||||
say " ✅ 兜底重启救回来了"
|
||||
remember "兜底" "$REASON"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
say ""
|
||||
say " ❌ 全部没解决。再采一次现场(状态已经变了)"
|
||||
collect "$REASON(多轮抢救后仍不通)"
|
||||
|
||||
{
|
||||
echo "⚠ 这份报告是「自动抢救全部失败」之后生成的。"
|
||||
echo " 机器自己试过了:重启中转 / 强杀重拉 / 查防火墙。"
|
||||
echo " 机器自己试过了:重载/重启 nginx、重启中转、强杀重拉。"
|
||||
echo " (重启整机默认没做。)"
|
||||
echo " 需要人工看一眼 —— 特别是 Lightsail **网页上的防火墙规则**,"
|
||||
echo " 需要人工看一眼 —— 特别是 **Lightsail 网页上的防火墙规则**,"
|
||||
echo " 那一层系统内部改不了。"
|
||||
echo
|
||||
cat "$REPORT"
|
||||
|
||||
Reference in New Issue
Block a user