群晖 NAS 监控 Cloudflare Tunnel 服务状态自动重启

大善人Cloudflare 提供了内网穿透服务,将没有公网IP的项目暴露到公网。
我在群晖NAS上安装了Cloudflare Tunnel套件,一般情况下都能够稳定运行,但在设备的长期运行中也出现了掉线的异常情况,通常重启一下群晖上的Cloudflare Tunnel套件就好。为了保障设备能够更加稳定的在线,设置一个新的任务计划:根据NAS上的web服务状态自动重启Cloudflare Tunnel套件。

#!/bin/bash

# 配置信息
URL="https://example.domain.com" # 群晖部署的网页
PACKAGE_NAME="cloudflared"  # 群晖套件名称
LOG_FILE="/volume1/docker/cloudflare_tunnel_monitor.log" #日志文件的目录
MAX_LOG_SIZE=10485760  # 10MB,日志文件最大大小
RETRY_COUNT=3         # 重试次数
RETRY_DELAY=5         # 重试间隔(秒)
WECOM_WEBHOOK="https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=替换成自己的机器人或删除"   # 企业微信的webhook,重启情况通知到企业微信。

# 日志函数
log_message() {
    local timestamp=$(date "+%Y-%m-%d %H:%M:%S")
    echo "[$timestamp] $1" >> "$LOG_FILE"

    # 检查日志文件大小,超过限制则截断
    if [ -f "$LOG_FILE" ] && [ $(stat -c%s "$LOG_FILE") -gt $MAX_LOG_SIZE ]; then
        tail -n 1000 "$LOG_FILE" > "$LOG_FILE.tmp"
        mv "$LOG_FILE.tmp" "$LOG_FILE"
    fi
}

# 发送企业微信通知
send_wecom_notice() {
    local message=$1
    local content=$(cat <<EOF
{
    "msgtype": "text",
    "text": {
        "content": "【Cloudflare Tunnel监控】\n$message\n服务器: $(hostname)\n时间: $(date "+%Y-%m-%d %H:%M:%S")"
    }
}
EOF
)

    curl -s -H "Content-Type: application/json" -d "$content" "$WECOM_WEBHOOK" >/dev/null
}

# 检查依赖
check_dependency() {
    command -v $1 >/dev/null 2>&1 || { log_message "错误: 需要 $1 但未找到。"; exit 1; }
}

# 检查网络连通性
check_network() {
    ping -c 3 8.8.8.8 >/dev/null 2>&1
    return $?
}

# 检查套件状态(运行中返回0,否则返回非0)
check_package_status() {
    synopkg status "$PACKAGE_NAME" "Status: Running"
    return $?
}

# 重启套件
restart_package() {
    log_message "尝试重启 $PACKAGE_NAME 套件..."
    send_wecom_notice "检测到站点[$URL]无法访问,正在重启Cloudflare Tunnel套件..."

    # 停止套件
    synopkg stop "$PACKAGE_NAME"
    sleep 10  # 等待停止

    # 启动套件
    synopkg start "$PACKAGE_NAME"

    # 验证状态
    sleep 15  # 等待启动
    if check_package_status; then
        log_message "$PACKAGE_NAME 套件已成功重启"
        send_wecom_notice "Cloudflare Tunnel套件重启成功,站点应已恢复访问"
    else
        log_message "错误: 重启 $PACKAGE_NAME 套件失败"
        send_wecom_notice "警告: Cloudflare Tunnel套件重启失败,请手动检查!"
    fi
}

# 主程序
main() {
    log_message "开始监控 $URL"

    # 检查依赖
    check_dependency "curl"
    check_dependency "ping"
    check_dependency "synopkg"  # 确保群晖套件管理工具可用

    # 检查网络连接
    if ! check_network; then
        log_message "错误: 网络连接失败,跳过站点检查"
        send_wecom_notice "警告: 服务器网络连接失败,Cloudflare Tunnel监控任务未执行!"
        exit 1
    fi

    # 检查站点可用性
    success=0
    for ((i=1; i<=$RETRY_COUNT; i++)); do
        response=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 10 --max-time 30 "$URL")

        if [ "$response" = "200" ]; then
            log_message "站点可访问 (HTTP $response)"
            success=1
            break
        else
            log_message "尝试 $i/$RETRY_COUNT: 站点不可访问 (HTTP $response)"
            sleep $RETRY_DELAY
        fi
    done

    # 如果多次尝试都失败,则重启套件
    if [ $success -eq 0 ]; then
        log_message "站点多次尝试均不可访问,准备重启 $PACKAGE_NAME 套件"
        restart_package
    fi

    log_message "监控完成"
}

# 执行主程序
main

这段代码的核心逻辑是对指定站点‘https://example.domain.com’进行定期访问检测,若检测到站点不可访问,便自动重启 Cloudflare Tunnel 服务,并通过企业微信 Webhook 发送通知。

将这段代码保存为Cloudflare.sh,保存到群晖目录。

  1. 配置计划任务
    • 打开 DSM 控制面板 > 任务计划
    • 创建新的计划任务,选择 “用户定义的脚本”
    • 设置执行频率(建议每 小时)
    • 在任务设置中,填入:Cloudflare.sh 文件位置
  2. 日志查看:脚本会将执行信息记录到 `/volume1/docker/cloudflare_tunnel_monitor.log

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

9 Comments

    • Vei

      Tunnel一般是比较稳定的,如果没有出现掉线的话可以把时间设置的更长,不影响休眠。

  1. 对于nas用户来说 Cloudflare Tunnel 确实是一个挺不错的省钱方式

    • Vei

      免费给超大杯,用来测试一些小服务还是不错的

  2. 看你们博客,发现都是网络技术相关,然后作为一个公司 IT,我却什么都看不懂……
    我只知道按正常使用去测试,遇到什么问题记录下来写邮件给供应商……

    • Vei

      我还是生活向更多一些,内容很杂乱。搞些代码都只是因为兴趣,怕以后忘了,在博客做一个记录。我也很羡慕你这样的甲方生活。

  3. 我更简单粗暴。我用 aws 做 frp,每天凌晨两点自动重启一次服务器。