自己用AI写的
优化鸡和普通鸡上部署好一模一样的面板,就可以实现非高峰期用普通鸡省流量,高峰期用优化鸡,无缝切换

#!/bin/bash
# ================= 配置区 =================
# Cloudflare 认证信息
CF_TOKEN="" # ⚠️ 注意:你的 Token 需要同时拥有 "DNS 修改" 和 "Workers KV 基础读取" 权限
ZONE_ID=""
ACCOUNT_ID="" # 💡 Cloudflare 账户 ID(在域名概述页右下角可以找到)
KV_NAMESPACE_ID="" # 💡 KV 命名空间 ID
# 域名全称 (如 test.example.com)
RECORD_NAME="example.com"
# 指定用于解析 SCHEDULE 中域名的 DNS 服务器
DNS_SERVER="8.8.4.4"
# 🌟 本地备份数据(格式: "HH:MM@域名:主TCP端口:备用TCP端口")
# 当 Cloudflare 网络故障、API 限制或获取不到云端配置时,作为保底死数据使用
SCHEDULE=(
"02:[email protected]:22:8080"
"18:[email protected]:22:8080"
)
# 是否开启 Cloudflare 代理
PROXIED=false
# TCP 探测超时时间(秒)
CHECK_TIMEOUT=2
# Bark 通知配置
BARK_SERVER="https://api.day.app"
BARK_KEY="" # ⚠️ 注意:请填写你自己的 Bark device Key
BARK_TITLE="🚀 节点切换通知"
# ==========================================
# Bark 发送通知函数
send_bark_notification() {
local message="$1"
local group="CF-Switch"
local encoded_message=$(jq -rn --arg msg "$message" '$msg | @uri')
local encoded_title=$(jq -rn --arg title "$BARK_TITLE" '$title | @uri')
curl -s -X GET "$BARK_SERVER/$BARK_KEY/$encoded_title/$encoded_message?group=$group" &>/dev/null
}
# 检查系统依赖
for cmd in jq dig nc; do
if ! command -v $cmd &> /dev/null; then
echo "❌ 错误: 未检测到必要工具 [$cmd],请先运行: sudo apt install jq dnsutils netcat-openbsd -y"
exit 1
fi
done
CURRENT_TIME=$(date +"%H:%M")
echo "=========================================================="
echo "⏰ 运行时间: $(date '+%Y-%m-%d %H:%M:%S') ($CURRENT_TIME)"
# ========================================================
# 🌟 核心优化:动态从 Cloudflare KV 获取最新的实时时间表
# ========================================================
echo "☁️ 正在尝试从 Cloudflare KV 同步最新时间表..."
KV_URL="https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/storage/kv/namespaces/$KV_NAMESPACE_ID/values/uk_schedule"
KV_RESPONSE=$(curl -s -w "\n%{http_code}" -X GET "$KV_URL" -H "Authorization: Bearer $CF_TOKEN")
HTTP_CODE=$(echo "$KV_RESPONSE" | tail -n 1)
KV_VALUE=$(echo "$KV_RESPONSE" | head -n -1)
if [ "$HTTP_CODE" -eq 200 ] && [ -n "$KV_VALUE" ] && [ "$KV_VALUE" != "null" ]; then
# 使用 jq 解析 JSON 数组并将其转换为 Bash 数组
readarray -t CLOUD_SCHEDULE < <(echo "$KV_VALUE" | jq -r '.[]')
if [ ${#CLOUD_SCHEDULE[@]} -gt 0 ]; then
SCHEDULE=("${CLOUD_SCHEDULE[@]}")
echo "✅ [云端同步] 成功加载 Cloudflare KV 实时时间表!节点数: ${#SCHEDULE[@]}"
fi
else
echo "⚠️ [降级预案] 无法从云端获取配置 (HTTP $HTTP_CODE)。切换为本地保底死数据。"
fi
# ========================================================
# 1. 匹配时段
TARGET_ENTRY=""
SORTED_SCHEDULE=$(printf "%s\n" "${SCHEDULE[@]}" | sort)
for entry in $SORTED_SCHEDULE; do
CONF_TIME=$(echo $entry | cut -d'@' -f1)
if [[ "$CURRENT_TIME" > "$CONF_TIME" ]] || [[ "$CURRENT_TIME" == "$CONF_TIME" ]]; then
TARGET_ENTRY=$entry
fi
done
[ -z "$TARGET_ENTRY" ] && TARGET_ENTRY=$(echo "$SORTED_SCHEDULE" | tail -n 1)
# 解析域名与双端口
TARGET_DOMAIN=$(echo "$TARGET_ENTRY" | cut -d'@' -f2 | cut -d':' -f1)
PORT_MAIN=$(echo "$TARGET_ENTRY" | cut -d'@' -f2 | cut -d':' -f2)
PORT_BACKUP=$(echo "$TARGET_ENTRY" | cut -d'@' -f2 | cut -d':' -f3)
echo "🔍 当前目标: $TARGET_DOMAIN (主端口: $PORT_MAIN / 备用: ${PORT_BACKUP:-无})"
# 2. 多 DNS 交叉解析(严格防御版:防止域名无效时误抓 DNS 自身 IP)
echo "🌐 正在解析域名..."
TARGET_IP=""
for dns in "$DNS_SERVER" "1.1.1.1"; do
# 🌟 增加严格过滤:dig 结果必须包含纯公网解析,且排除掉传入的 DNS 变量自身
RAW_DIG=$(dig @$dns +short +time=2 +tries=1 "$TARGET_DOMAIN" 2>/dev/null)
if [ -n "$RAW_DIG" ] && [ "$RAW_DIG" != "$dns" ]; then
TARGET_IP=$(echo "$RAW_DIG" | grep -E -o '([0-9]{1,3}\.){3}[0-9]{1,3}' | head -n 1)
[ -n "$TARGET_IP" ] && break
fi
done
# 如果真的解析不到(比如域名写错了,或者国外DNS还没生效)
if [ -z "$TARGET_IP" ]; then
echo "❌ [DNS 错误] 无法解析域名 [$TARGET_DOMAIN]!请检查该域名是否已在公网配置 A 记录。"
echo "🛑 本次操作终止。"
exit 1
fi
echo "🎯 解析结果: $TARGET_IP"
# 3. 智能双端口复合探测
echo "📡 正在进行网络可用性测试..."
IS_ALIVE=false
DETECTED_PORT=""
if nc -z -w $CHECK_TIMEOUT $TARGET_IP $PORT_MAIN &>/dev/null; then
IS_ALIVE=true
DETECTED_PORT=$PORT_MAIN
elif [ -n "$PORT_BACKUP" ] && nc -z -w $CHECK_TIMEOUT $TARGET_IP $PORT_BACKUP &>/dev/null; then
IS_ALIVE=true
DETECTED_PORT=$PORT_BACKUP
echo "💡 提示: 主端口 $PORT_MAIN 好像没通,但备用端口 $PORT_BACKUP 响应正常。"
fi
if [ "$IS_ALIVE" = false ]; then
echo "⚠️ [安全拦截] 目标服务器 $TARGET_IP 端口全灭!已取消本次切换。"
exit 0
fi
# 4. 获取 CF 当前状态
RECORD_INFO=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records?name=$RECORD_NAME&type=A" \
-H "Authorization: Bearer $CF_TOKEN" \
-H "Content-Type: application/json")
RECORD_ID=$(echo $RECORD_INFO | jq -r '.result[0].id')
CURRENT_CF_IP=$(echo $RECORD_INFO | jq -r '.result[0].content')
if [ "$RECORD_ID" == "null" ] || [ -z "$RECORD_ID" ]; then
echo "❌ [CF 错误] 无法获取 $RECORD_NAME 的 A 记录。"
exit 1
fi
if [ "$TARGET_IP" == "$CURRENT_CF_IP" ]; then
echo "💤 解析已是最新 ($TARGET_IP),无需改动。"
exit 0
fi
# 5. 执行平滑切换并推送通知
echo "🔄 正在将 $RECORD_NAME 切换至 $TARGET_IP..."
UPDATE_RESULT=$(curl -s -X PATCH "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/$RECORD_ID" \
-H "Authorization: Bearer $CF_TOKEN" \
-H "Content-Type: application/json" \
--data "{\"content\": \"$TARGET_IP\", \"proxied\": $PROXIED}")
if [[ $(echo $UPDATE_RESULT | jq -r '.success') == "true" ]]; then
msg="切换目标:$RECORD_NAME
时段匹配:$TARGET_DOMAIN
新IP地址:$TARGET_IP
原IP地址:$CURRENT_CF_IP
探测端口:$DETECTED_PORT 通畅"
echo "$msg"
send_bark_notification "$msg"
else
echo "❌ [切换失败] CF 返回错误: $(echo $UPDATE_RESULT | jq -r '.errors[0].message')"
fi


这个不错,比 ddnsgo 还轻量
没搞太懂,是做什么的,NAT鸡用的吗
@pursuer #2 定时切换dns
改DDNS
闲事解析到闲时也快乐的机
忙时解析到顶尖机
定时跑脚本
也算一个小技巧
@clear778 #3 明白了,就是高低峰阶段将域名解析到普通/优化线路上,是这样吗
@pursuer #5 是这意思
已收藏,周末玩玩
@clear778 #6 好东西
KV 做动态时间表这个思路挺实用,建议再加个变更日志,排查误切换会方便很多。
@justin90 #9 日志都齐全的