早起发现小主机内网服务器的公网访问失败,cloudflare显示错误码:531,提示服务器不在线。本文记录了修复过程。

服务是运行在有ipv6公网地址的内网小主机上,通过ddns到cf。
经查是路由器lan ipv6变成2001开头的地址,给小主机下发的地址也是2001开头的地址,这种情况下必须重启路由器,重新拨号才能恢复成2409开头的地址。

修复脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#!/bin/bash
# 检测 IPv6 前缀,异常时通过 ntfy/企业微信/钉钉/飞书 发送提醒
# 适用:Debian 系 NAS,ip 命令位于 /usr/sbin/ip

# ============ 配置区 ============
EXPECTED_PREFIX="2409" # 期望的 IPv6 前缀
LOG_FILE="/var/log/ipv6_check.log" # 日志路径
COOLDOWN_FILE="/tmp/ipv6_check_last_alert"
COOLDOWN_SECONDS=1800 # 两次告警最小间隔(秒),30分钟

# 通知方式:填了哪个就用哪个,可同时启用多个
NTFY_URL="***" # 例如 https://ntfy.sh/your-topic
WECOM_WEBHOOK="" # 企业微信机器人 webhook
DINGTALK_WEBHOOK="" # 钉钉机器人 webhook
FEISHU_WEBHOOK="" # 飞书机器人 webhook
# ================================

IP_CMD="/usr/sbin/ip"

log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
}

# 冷却判断:距上次告警不足 COOLDOWN_SECONDS 就跳过
if [ -f "$COOLDOWN_FILE" ]; then
last_alert=$(cat "$COOLDOWN_FILE" 2>/dev/null)
now=$(date +%s)
if [ -n "$last_alert" ] && [ $((now - last_alert)) -lt $COOLDOWN_SECONDS ]; then
log "处于冷却期,跳过本次检测"
exit 0
fi
fi

# 获取本机所有全局 IPv6 地址(排除 link-local 和回环)
ipv6_list=$($IP_CMD -6 addr show scope global 2>/dev/null \
| grep -oP 'inet6 \K[0-9a-f:]+' \
| grep -vi '^fe80' \
| grep -vi '^::1')

if [ -z "$ipv6_list" ]; then
log "未检测到全局 IPv6 地址"
exit 0
fi

log "检测到 IPv6 地址:$(echo $ipv6_list | tr '\n' ' ')"

# 检查是否至少有一个地址以期望前缀开头
bad_addrs=""
ok_count=0
for addr in $ipv6_list; do
if [[ "$addr" == ${EXPECTED_PREFIX}* ]]; then
ok_count=$((ok_count + 1))
else
bad_addrs="$bad_addrs $addr"
fi
done

if [ "$ok_count" -gt 0 ]; then
log "前缀正常(${EXPECTED_PREFIX}开头),无需告警"
exit 0
fi

# 全部异常,触发告警
msg="路由器 IPv6 前缀异常!
期望前缀:${EXPECTED_PREFIX}
实际地址:${bad_addrs}
时间:$(date '+%Y-%m-%d %H:%M:%S')
请手动重启路由器。"

log "触发告警:$msg"
echo "$(date +%s)" > "$COOLDOWN_FILE"

# ---- 发送通知 ----
# ntfy
if [ -n "$NTFY_URL" ]; then
curl -s -d "$msg" "$NTFY_URL" > /dev/null
log "已发送 ntfy 通知"
fi

# 企业微信
if [ -n "$WECOM_WEBHOOK" ]; then
curl -s -H "Content-Type: application/json" \
-d "{\"msgtype\":\"text\",\"text\":{\"content\":\"$msg\"}}" \
"$WECOM_WEBHOOK" > /dev/null
log "已发送企业微信通知"
fi

# 钉钉
if [ -n "$DINGTALK_WEBHOOK" ]; then
curl -s -H "Content-Type: application/json" \
-d "{\"msgtype\":\"text\",\"text\":{\"content\":\"$msg\"}}" \
"$DINGTALK_WEBHOOK" > /dev/null
log "已发送钉钉通知"
fi

# 飞书
if [ -n "$FEISHU_WEBHOOK" ]; then
curl -s -H "Content-Type: application/json" \
-d "{\"msg_type\":\"text\",\"content\":{\"text\":\"$msg\"}}" \
"$FEISHU_WEBHOOK" > /dev/null
log "已发送飞书通知"
fi

保存为ipv6_check.sh

1
2
chmod +x ipv6_check.sh
./ipv6_check.sh

放到cron中:

1
*/10 * * * * /bin/bash /root/ipv6_check.sh

每十分钟执行一次,检测到ipv6地址不是以2409开头就用ntfy,企业微信等方式提醒手动重启路由器,主机地址刷新后重新ddns新地址,问题解决。