暂无描述

Dew-OF-Aurora fe7d3bd231 fix: for doc 1 周之前
scripts 3fa3f06107 feature: router mode 1 周之前
substore 43c0c602db feature: add router mode 1 周之前
.gitignore 3fa3f06107 feature: router mode 1 周之前
CLAUDE.md 3fa3f06107 feature: router mode 1 周之前
README.md 3fa3f06107 feature: router mode 1 周之前
config.router.json 43c0c602db feature: add router mode 1 周之前
config.server.json 43c0c602db feature: add router mode 1 周之前
router_local.conf 3fa3f06107 feature: router mode 1 周之前
workflow.md 3fa3f06107 feature: router mode 1 周之前

README.md

vmess-domain-rotator

一个用于选择优选目标并写出运行时文件的工具集,当前支持两套独立模式:

  • 云服务器模式:调用远程 API,选择优选域名,写入 runtime/,可自动提交到 runtime-state
  • 本地路由器模式:调用本地 cfst,选择优选 IP,写入 cfip_runtime/;HTTP 暴露推荐使用项目目录下的完整 BusyBox httpd

这两套模式已经彻底拆开:

旧的 config.json / config.example.json 已废弃,不再使用。

1. 目录与入口

核心脚本:

  • scripts/domain_updater.py 统一的 Python 主入口,支持 apicfst_local 两种 source.type
  • scripts/run_update_and_commit.sh 服务器模式入口,执行 updater 并按配置同步运行时文件到 runtime-state
  • scripts/install_debian.sh Debian/Ubuntu 一键安装 systemd service + timer
  • scripts/uninstall_debian.sh 卸载 systemd service + timer
  • scripts/router_local_update.sh BusyBox sh 路由器入口,执行 cfst 并写出 cfip_runtime
  • scripts/router_local_http.sh BusyBox sh 路由器 HTTP 暴露入口,优先使用 BusyBox httpd 暴露运行时文件
  • scripts/update_vmess_links.py 可选工具,用运行时文件里的值批量替换 vmess:// 节点

配置文件:

  • config.server.json 服务器模式配置,输出默认是:
    • runtime/current_domain.txt
    • runtime/current_domain.json
    • runtime/state.json
    • runtime/substore_vars.json
  • config.router.json 本地 cfst 模式配置,输出默认是:
    • cfip_runtime/current_ip.txt
    • cfip_runtime/current_ip.json
    • cfip_runtime/state.json
    • cfip_runtime/substore_vars.json
  • router_local.conf BusyBox 路由器脚本配置,给 router_local_update.sh / router_local_http.sh 使用

2. 共用设计

两套模式共用同一套“输出抽象”:

  • 文本值文件:当前选中的值
  • JSON 文件:当前结果
  • state 文件:上次可用值和状态
  • export vars 文件:给外部系统消费

关键点:

  • 输出文件名和输出目录都从配置读取,不再在 shell 脚本里硬编码 runtime/current_domain.txt
  • run_update_and_commit.sh 会先解析配置里的输出路径,再决定同步哪些文件
  • 只有服务器模式默认集成 git commit/push;路由器模式不做 git 操作
  • domain_updater.py 会按 --config 所在目录解析相对路径

3. 模式选择

3.1 云服务器模式

适用场景:

  • python3
  • 有网络访问目标 API
  • 需要 systemd 定时执行
  • 需要自动提交 runtime-state

入口:

  • 手动执行:python3 scripts/domain_updater.py --config config.server.json
  • 定时执行:bash scripts/run_update_and_commit.sh config.server.json
  • Debian 安装:sudo bash scripts/install_debian.sh --config config.server.json

3.2 本地 cfst 模式

适用场景:

  • 在本机、Mac、Linux 上已有可执行的 cfst
  • 希望由 domain_updater.py 直接调用本地 cfst
  • 不需要 BusyBox 专用脚本

入口:

  • python3 scripts/domain_updater.py --config config.router.json

3.3 BusyBox 路由器模式

适用场景:

  • 路由器没有 Python
  • 只有 BusyBox sh / awk / sed 等基础工具即可执行更新脚本
  • HTTP 暴露推荐使用项目目录下的完整 BusyBox,例如 BUSYBOX_BIN="./busybox_armv7l",脚本会调用它的 httpd applet;系统自带精简 nc 不够

入口:

  • 更新结果:sh scripts/router_local_update.sh ./router_local.conf
  • 暴露 HTTP:sh scripts/router_local_http.sh ./router_local.conf

4. 云服务器模式部署

4.1 前置条件

  • Debian/Ubuntu
  • git clone 后在仓库目录执行
  • 远程仓库已配置,例如 origin
  • 运行用户对仓库有读写权限
  • 机器上可访问 config.server.json 中的 API

4.2 核心配置文件

服务器模式固定使用 config.server.json

它当前默认行为:

  • source.type = "api"
  • 通过 api.url 拉取候选结果
  • 通过 parserrecord_mappingrecord_filterscoring 选择目标
  • 写出到 runtime/

你通常只需要修改:

  • api.url
  • api.headers
  • parser
  • record_mapping
  • record_filter
  • scoring
  • healthcheck

4.3 本地手动跑通

先做语法检查:

env PYTHONPYCACHEPREFIX=/tmp/pycache python3 -m py_compile scripts/domain_updater.py

执行一次:

python3 scripts/domain_updater.py --config config.server.json

查看结果:

cat runtime/current_domain.txt
cat runtime/current_domain.json
cat runtime/state.json
cat runtime/substore_vars.json

如果你只想看脚本解析出的输出路径:

python3 scripts/domain_updater.py --config config.server.json --print-output-settings

4.4 自动提交到 runtime-state

服务器模式提交脚本:

bash scripts/run_update_and_commit.sh config.server.json

它会执行:

  1. 调用 domain_updater.py
  2. 从配置解析出运行时文件路径
  3. 比较本次“选中值”和 runtime-state 分支上次记录
  4. 值未变化时跳过 commit/push
  5. 值变化时同步配置定义的输出文件并提交

强制提交:

bash scripts/run_update_and_commit.sh --force-commit config.server.json

或:

GIT_FORCE_COMMIT=1 bash scripts/run_update_and_commit.sh config.server.json

4.5 Debian 一键安装

推荐命令:

sudo bash scripts/install_debian.sh --config config.server.json

默认行为:

  • 使用当前 sudo 前的用户作为 service 用户
  • 定时周期 1h
  • 自动 push 开启
  • 目标分支 runtime-state

常用参数:

sudo bash scripts/install_debian.sh \
  --config config.server.json \
  --interval 10min \
  --git-push 1 \
  --git-push-remote origin

如果用 token:

sudo bash scripts/install_debian.sh \
  --config config.server.json \
  --git-http-username <your-user> \
  --git-http-token-file /root/.config/vmess-token \
  --git-use-credential-store 1

4.6 安装后验证

sudo systemctl status vmess-domain-rotator.timer
sudo systemctl status vmess-domain-rotator.service
sudo systemctl start vmess-domain-rotator.service
sudo journalctl -u vmess-domain-rotator.service -n 120 --no-pager

成功时通常应看到:

  • updater 输出 JSON
  • committed output changes on runtime-state
  • pushed to origin/runtime-state

4.7 卸载

sudo bash scripts/uninstall_debian.sh

保留认证文件:

sudo bash scripts/uninstall_debian.sh --keep-auth-files

5. 本地 cfst 模式部署

5.1 适用环境

  • python3
  • 有可执行的 cfst
  • 不依赖 BusyBox
  • 希望继续复用 domain_updater.py 的统一输出逻辑

5.2 核心配置文件

本模式使用 config.router.json

它当前默认指向:

  • ./cfst_darwin_arm64/cfst
  • 结果文件 ./cfst_darwin_arm64/result.csv
  • 输出目录 ./cfip_runtime

你通常只需要修改:

  • cfst_local.work_dir
  • cfst_local.binary
  • cfst_local.run_args
  • cfst_local.result_file
  • cfst_local.columns
  • output.*

5.3 手动执行

python3 scripts/domain_updater.py --config config.router.json

查看结果:

cat cfip_runtime/current_ip.txt
cat cfip_runtime/current_ip.json
cat cfip_runtime/state.json
cat cfip_runtime/substore_vars.json

查看解析出的输出路径:

python3 scripts/domain_updater.py --config config.router.json --print-output-settings

5.4 配置说明

cfst_local 关键项:

  • work_dir cfst 工作目录
  • binary cfst 可执行文件路径
  • run_args 执行参数数组,例如 -f ip.txt -o result.csv -p 10
  • result_file cfst 输出结果文件
  • skip_runtrue 时不执行 cfst,只解析现有结果文件
  • columns CSV 列映射,默认按:
    • 0 IP
    • 1 已发送
    • 2 已接收
    • 3 丢包率
    • 4 平均延迟
    • 5 下载速度
    • 6 地区

6. BusyBox 路由器模式部署

6.1 适用环境

  • 路由器没有 Python
  • 已准备对应架构的 cfst
  • 已准备完整 BusyBox,例如本项目默认使用 busybox_armv7l
  • HTTP 暴露使用完整 BusyBox 的 httpd applet,不使用 ASUS 固件自带 /usr/sbin/httpd

架构以目标路由器实际输出为准:

uname -m

cfst 和完整 BusyBox 都必须匹配路由器架构。ASUS RT-AC68U 示例里,完整 BusyBox 文件名使用 busybox_armv7l

6.2 路由器目录建议

示例(ASUS RT-AC68U 推荐放在 /jffs/vmess):

/jffs/vmess/
├── busybox_armv7l
├── router_local.conf
├── scripts/
│   ├── router_local_update.sh
│   └── router_local_http.sh
└── cfst/
    ├── cfst
    ├── ip.txt
    └── result.csv

其中:

  • router_local.conf 指定 CFST_WORK_DIR、输出目录、HTTP 端口、完整 BusyBox 路径等
  • busybox_armv7l 是你下载的完整 BusyBox,HTTP 服务脚本会优先调用它,而不是系统自带 BusyBox/ASUS httpd
  • cfst/ 放路由器架构对应的 cfst

6.3 配置 router_local.conf

当前仓库里的 router_local.conf 就是 BusyBox 配置文件。

最重要的字段:

  • CFST_WORK_DIR cfst 所在目录
  • CFST_BIN cfst 可执行文件名,一般是 ./cfst
  • CFST_IP_FILE 输入 IP 列表
  • CFST_RESULT_FILE cfst 结果文件
  • RUNTIME_DIR 运行时输出目录,默认 ./cfip_runtime
  • VALUE_TEXT_FILE 当前值文本文件,默认 current_ip.txt
  • VALUE_JSON_FILE 当前值 JSON 文件,默认 current_ip.json
  • BUSYBOX_BIN 完整 BusyBox 二进制路径,默认 ./busybox_armv7l;HTTP 脚本会优先调用它的 httpd applet,避免误用 ASUS /usr/sbin/httpd
  • HTTP_PORT 局域网 HTTP 监听端口,默认 8080

6.4 手动更新一次

sh scripts/router_local_update.sh ./router_local.conf

成功时会输出类似:

[router-local] selected ip: x.x.x.x

生成文件默认在:

  • cfip_runtime/current_ip.txt
  • cfip_runtime/index.html(复制当前 IP 文本,供 / 访问)
  • cfip_runtime/current_ip.json
  • cfip_runtime/state.json
  • cfip_runtime/substore_vars.json

6.5 暴露到局域网

sh scripts/router_local_http.sh ./router_local.conf

默认会监听:

0.0.0.0:8080

这个脚本不再使用系统自带的精简 nc 或 ASUS /usr/sbin/httpd。它会读取 router_local.conf 里的 BUSYBOX_BIN,优先调用项目目录下完整 BusyBox 的 httpd applet:

./busybox_armv7l httpd -f -p 8080 -h ./cfip_runtime

如果你的 BusyBox applet 列表里没有 httpd,当前脚本会明确报错。ASUS 固件自带的 /usr/sbin/httpd 通常是路由器管理后台服务,不是 BusyBox 静态文件服务器;即使支持 -p 端口参数,也不代表支持 -h ./cfip_runtime 这类目录发布。

可访问路径:

  • /(由 index.html 返回当前 IP 文本)
  • /current_ip.txt
  • /current_ip.json
  • /state.json
  • /substore_vars.json

例如局域网内访问:

curl http://192.168.50.1:8080/current_ip.json
curl http://192.168.50.1:8080/current_ip.txt

6.6 ASUS RT-AC68U services-start 自启动

如果路由器使用 /jffs/scripts/services-start 统一启动任务,可以用 cru 注册定时更新和 watchdog。这个小节是 ASUS RT-AC68U / KoolShare 风格固件专用示例,假设项目放在 /jffs/vmess,完整 BusyBox 位于 /jffs/vmess/busybox_armv7l

部署前建议确认:

chmod +x /jffs/vmess/busybox_armv7l
chmod +x /jffs/scripts/services-start
/jffs/vmess/busybox_armv7l --list | grep '^httpd$'

router_local.conf 至少需要包含:

BUSYBOX_BIN="./busybox_armv7l"
HTTP_PORT="8080"

/jffs/scripts/services-start 写成:

#!/bin/sh
/koolshare/bin/ks-services-start.sh

VMESS_DIR="/jffs/vmess"
CONFIG="./router_local.conf"
UPDATE_LOG="/tmp/router_local_update.log"
HTTP_LOG="/tmp/router_http.log"

start_vmess_http() {
  if ps | grep -v grep | grep -q 'router_local_http.sh'; then
    return 0
  fi

  cd "$VMESS_DIR" || exit 1
  nohup sh scripts/router_local_http.sh "$CONFIG" >> "$HTTP_LOG" 2>&1 &
}

cd "$VMESS_DIR" || exit 1
sh scripts/router_local_update.sh "$CONFIG" >> "$UPDATE_LOG" 2>&1

cru d vmess_rotate
cru a vmess_rotate "0 */3 * * * cd $VMESS_DIR && sh scripts/router_local_update.sh $CONFIG >> $UPDATE_LOG 2>&1"

sleep 10
start_vmess_http

cru d vmess_watchdog
cru a vmess_watchdog "*/5 * * * * if ! ps | grep -v grep | grep -q 'router_local_http.sh'; then cd $VMESS_DIR && nohup sh scripts/router_local_http.sh $CONFIG >> $HTTP_LOG 2>&1 & fi"

router_local_http.sh 会保留 wrapper 进程并等待子进程里的完整 BusyBox httpd,所以 watchdog 用 router_local_http.sh 作为进程关键字可以正常判断服务是否仍在运行。示例里先 cru dcru a,避免 services-start 被重复触发后留下旧的定时任务定义;启动 HTTP 前也会先检查进程,避免重复监听同一个端口。

6.7 定时执行

可以用 BusyBox crond 定时更新,例如每 15 分钟执行一次:

*/15 * * * * cd /tmp/home/root/vmess-domain-rotator && sh scripts/router_local_update.sh ./router_local.conf >> /tmp/router_local_update.log 2>&1

6.8 手动常驻 HTTP

HTTP 服务如果需要手动后台启动:

cd /tmp/home/root/vmess-domain-rotator
nohup sh scripts/router_local_http.sh ./router_local.conf >/tmp/router_http.log 2>&1 &

7. VMess 链接批量替换

如果下游要消费“当前值文件”,可使用 scripts/update_vmess_links.py

服务器模式示例:

python3 scripts/update_vmess_links.py \
  --input ./nodes.txt \
  --output ./nodes.updated.txt \
  --domain-file ./runtime/current_domain.txt

路由器/本地 cfst 模式示例:

python3 scripts/update_vmess_links.py \
  --input ./nodes.txt \
  --output ./nodes.updated.txt \
  --domain-file ./cfip_runtime/current_ip.txt

仅替换匹配名称的节点:

python3 scripts/update_vmess_links.py \
  --input ./nodes.txt \
  --output ./nodes.updated.txt \
  --domain-file ./runtime/current_domain.txt \
  --name-regex "(argo|cf|vm)"

8. 常用运维命令

服务器模式:

sudo systemctl status vmess-domain-rotator.timer
sudo systemctl status vmess-domain-rotator.service
sudo systemctl start vmess-domain-rotator.service
sudo journalctl -u vmess-domain-rotator.service -f
git log runtime-state --oneline -n 20

路由器模式:

sh scripts/router_local_update.sh ./router_local.conf
sh scripts/router_local_http.sh ./router_local.conf
cat cfip_runtime/current_ip.txt
cat cfip_runtime/current_ip.json

9. 注意事项

  1. 服务器模式和路由器模式的配置不要混用。
  2. run_update_and_commit.sh 设计目标是服务器模式;路由器模式默认不走 git 提交。
  3. 服务器模式下,service 用户和 git 凭证用户必须一致,否则会出现 terminal prompts disabled
  4. credential.helper store 是明文存储,只适合可控服务器。
  5. BusyBox 路由器模式下,router_local_update.sh 只依赖常见基础 applet;HTTP 暴露会优先调用 BUSYBOX_BIN 指向的完整 BusyBox httpd,不要依赖 ASUS /usr/sbin/httpd 或系统精简 nc
  6. state.json 需要持久化,否则 fallback 不可用。