Skip to content

Clash 定时更新与任务调度实战:Cron、系统计划任务与热重载 ​

直接答案:在企业办公网络、软路由与跨国开发环境中,代理系统必须具备全自动无人值守的定时更新与容灾自愈能力。服务商节点每隔数周可能调整入口 BGP IP 或更换证书,GeoIP 数据库每周都会发布全球 IP 归属更新。如果依赖人工手动点击更新,势必在节点变动时遭遇突发断网。真正的自动化架构由两层构成:第一层是内核内置的 Provider 周期轮询,第二层是依托 Linux Crontab / Systemd Timer / Windows 计划任务拉取最新规则并向 RESTful API 派发热重载指令,实现 0 断流秒级热更新。


一、双层定时更新机制架构 ​

为了兼顾“外部节点经常更新”与“主分流规则偶尔微调”的不同生命周期,生产环境应拆分为轻量资源内置轮询与全局主配置系统编排的双层拓扑:

+-------------------------------------------------------------------------+
| 第一层:内核内置周期轮询 (In-Kernel Pollers)                             |
|                                                                         |
| - proxy-providers (interval: 43200) -> 静默拉取最新节点并落盘缓存       |
| - rule-providers  (interval: 86400) -> 增量同步 GeoIP / 广告规则集       |
+-------------------------------------------------------------------------+
                                    |
+-------------------------------------------------------------------------+
| 第二层:操作系统守护级任务调度 (OS Daemon Schedulers)                   |
|                                                                         |
| [Linux Crontab / Systemd Timer] 或 [Windows Task Scheduler]             |
|                               |                                         |
| 1. 定时触发远程订阅拉取脚本   |                                         |
| 2. 校验文件完整性与 YAML 语法 |                                         |
| 3. 原子化替换本地配置快照     v                                         |
| 4. 向 Clash RESTful API 发起 PUT /configs ──> [0 丢包热重载内核生效]   |
+-------------------------------------------------------------------------+

二、Linux 生产级 Shell 定时拉取与原子热重载脚本 ​

以下是一份具备错误拦截、YAML 格式预检、故障自动回滚与无感热重载的企业级 Shell 脚本(保存为 /opt/clash/update_config.sh):

bash
#!/usr/bin/env bash
# ==============================================================================
# Clash / Mihomo 生产级全自动定时拉取与热重载脚本
# 功能:下载最新订阅 -> 校验 HTTP 响应 -> 验证 YAML 语法 -> 原子覆盖 -> API 热重载
# ==============================================================================
set -euo pipefail

# 1. 配置参数定义
SUB_URL="https://sub.your-airport-domain.com/api/v1/client/subscribe?token=SecretToken"
CONFIG_DIR="/etc/clash"
ACTIVE_CONFIG="${CONFIG_DIR}/config.yaml"
BACKUP_CONFIG="${CONFIG_DIR}/config.yaml.bak"
TEMP_CONFIG="${CONFIG_DIR}/config.yaml.tmp"
API_URL="http://127.0.0.1:9090/configs"
API_SECRET="YourDashboardSecretToken2026"
USER_AGENT="Clash/Mihomo-Automation-Agent"

echo "[$(date '+%Y-%m-%d %H:%M:%S')] 开始执行 Clash 自动化更新流水线..."

# 2. 安全拉取最新配置文件至临时文件
HTTP_CODE=$(curl -s -w "%{http_code}" -L \
  -H "User-Agent: ${USER_AGENT}" \
  --connect-timeout 15 \
  --max-time 60 \
  "${SUB_URL}" \
  -o "${TEMP_CONFIG}")

if [ "${HTTP_CODE}" != "200" ]; then
  echo "[错误] 远程订阅拉取失败,HTTP 响应码: ${HTTP_CODE}。终止更新,保持当前配置!"
  rm -f "${TEMP_CONFIG}"
  exit 1
fi

# 3. 基础非空校验与 YAML 语法基本检查
FILE_SIZE=$(wc -c < "${TEMP_CONFIG}")
if [ "${FILE_SIZE}" -lt 500 ]; then
  echo "[错误] 下载的文件体积过小 (${FILE_SIZE} 字节),疑似触发服务商防刷拦截,终止更新!"
  rm -f "${TEMP_CONFIG}"
  exit 1
fi

if ! grep -q "proxies:" "${TEMP_CONFIG}" && ! grep -q "proxy-providers:" "${TEMP_CONFIG}"; then
  echo "[错误] 下载内容缺少合法代理字段,格式不合法!终止更新!"
  rm -f "${TEMP_CONFIG}"
  exit 1
fi

# 4. 备份当前正在运行的有效配置,并原子化替换
if [ -f "${ACTIVE_CONFIG}" ]; then
  cp "${ACTIVE_CONFIG}" "${BACKUP_CONFIG}"
fi
mv "${TEMP_CONFIG}" "${ACTIVE_CONFIG}"
echo "[成功] 本地配置文件已安全原子化更新。"

# 5. 调用 RESTful 外部控制 API 发送热重载指令
RELOAD_STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X PUT "${API_URL}" \
  -H "Authorization: Bearer ${API_SECRET}" \
  -H "Content-Type: application/json" \
  -d "{\"path\": \"${ACTIVE_CONFIG}\", \"payload\": \"\"}")

if [ "${RELOAD_STATUS}" = "204" ] || [ "${RELOAD_STATUS}" = "200" ]; then
  echo "[成功] Clash 内核已完成 0 断流热重载!最新规则与节点已全面生效。"
else
  echo "[警告] 内核 API 热重载返回异常状态码: ${RELOAD_STATUS},正在尝试回退至备份..."
  if [ -f "${BACKUP_CONFIG}" ]; then
    cp "${BACKUP_CONFIG}" "${ACTIVE_CONFIG}"
    curl -s -X PUT "${API_URL}" -H "Authorization: Bearer ${API_SECRET}" -d "{\"path\": \"${ACTIVE_CONFIG}\"}"
  fi
  exit 1
fi

赋予执行权限并挂载 Crontab 计划任务 ​

bash
chmod +x /opt/clash/update_config.sh

# 打开当前用户的计划任务列表
crontab -e

# 添加如下定时调度规则:每天凌晨 04:30 自动执行一次更新
30 4 * * * /opt/clash/update_config.sh >> /var/log/clash_update.log 2>&1

三、基于 Systemd Timer 的现代化守护方案 ​

在较新的 Ubuntu / Debian / CentOS 服务器上,使用 Systemd Timer 相比传统 Crontab 能提供更精细的启动依赖控制、系统日志集成(journalctl)与随机抖动(Jitter 防止瞬时集中请求):

1. 创建 Service 单元:/etc/systemd/system/clash-updater.service ​

ini
[Unit]
Description=Clash Automated Configuration Updater
After=network-online.target clash.service
Wants=network-online.target

[Service]
Type=oneshot
ExecStart=/opt/clash/update_config.sh
StandardOutput=journal
StandardError=journal

2. 创建 Timer 单元:/etc/systemd/system/clash-updater.timer ​

ini
[Unit]
Description=Run Clash Configuration Updater Daily

[Timer]
OnCalendar=*-*-* 04:00:00
RandomizedDelaySec=1800
Persistent=true

[Install]
WantedBy=timers.target

执行激活指令:

bash
systemctl daemon-reload
systemctl enable --now clash-updater.timer
systemctl list-timers | grep clash

四、Windows 平台的 PowerShell 定时任务实操 ​

在 Windows 11 或 Windows Server 环境中,可通过 PowerShell 脚本配合系统任务计划程序(Task Scheduler)实现相同效果:

powershell
# 保存为 Update-Clash.ps1
$SubUrl = "https://sub.your-airport-domain.com/api/v1/client/subscribe?token=SecretToken"
$DestPath = "$env:USERPROFILE\.config\clash\config.yaml"
$TempPath = "$DestPath.tmp"

try {
    Invoke-WebRequest -Uri $SubUrl -OutFile $TempPath -TimeoutSec 30 -UserAgent "Clash/Mihomo"
    if ((Get-Item $TempPath).Length -gt 1000) {
        Move-Item -Path $TempPath -Destination $DestPath -Force
        # 触发本地 API 重载
        $Headers = @{ "Authorization" = "Bearer YourSecret" }
        $Body = @{ path = $DestPath } | ConvertTo-Json
        Invoke-RestMethod -Uri "http://127.0.0.1:9090/configs" -Method Put -Headers $Headers -Body $Body -ContentType "application/json"
        Write-Output "[$(Get-Date)] Clash 配置定时热重载成功!"
    }
} catch {
    Write-Error "更新失败: $_"
}

五、延伸阅读与相关方案 ​