|
|
há 2 semanas atrás | |
|---|---|---|
| scripts | há 2 semanas atrás | |
| substore | há 3 semanas atrás | |
| .gitignore | há 2 semanas atrás | |
| CLAUDE.md | há 2 semanas atrás | |
| README.md | há 2 semanas atrás | |
| config.example.json | há 2 semanas atrás | |
| config.json | há 2 semanas atrás | |
| workflow.md | há 2 semanas atrás |
一个用于 自动获取优选域名、写入 runtime/ 运行时文件,并按计划将运行时变更提交到 runtime-state 分支的工具。
本项目主要完成以下流程:
runtime/runtime-state核心脚本:
scripts/domain_updater.py:执行域名拉取、选择与写文件scripts/run_update_and_commit.sh:执行 updater + git 提交/推送scripts/install_debian.sh:Debian 下安装 systemd service + timerscripts/uninstall_debian.sh:卸载 systemd 与认证环境文件默认写入仓库根目录 runtime/:
runtime/current_domain.txt:当前域名(纯文本)runtime/current_domain.json:当前结果 JSONruntime/state.json:状态文件(含 last_good_domain)runtime/substore_vars.json:给外部系统消费的变量注意:
domain_updater.py现在会按--config文件所在目录解析output.runtime_dir(默认./runtime),避免误写到scripts/runtime/。注意:
main分支通常不追踪runtime/(由.gitignore忽略),运行时产物建议通过runtime-state分支消费。
编辑 config.json(可先从 config.example.json 复制一份再按你的 API 调整)。
典型解析路径(如 API 返回 data.good[].ip):
"parser": {
"field_paths": ["data.good[].ip"],
"json_paths": [],
"regex": "[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}"
}
你可以为不同 API 使用同一套脚本,只调整配置:
api:请求地址、方法、header、query 参数、超时parser:如何从返回 JSON 提取候选域名record_mapping:必填白名单字段注册表(后续过滤/评分只能引用这里登记的逻辑字段)record_filter:按记录字段做排除(个性化策略应放这里)domain_filter:按域名字符串做 include/excludescoring:如何按配置字段排序(支持 weighted_average / lexicographic)healthcheck:可选 TLS 检测selection:候选截断数量output:runtime 文件输出路径与文件名v2ray:模板替换输出(可选)notify:后置命令回调(可选)record_mapping 最小必填示例(domain 与 created_at 必须注册):
"record_mapping": {
"records_path": "data.good[]",
"field_map": {
"domain": "ip",
"created_at": "createdTime",
"avg_score": "avgScore"
},
"created_time_formats": ["%Y-%m-%d %H:%M:%S"],
"created_time_timezone": "UTC"
}
record_filter 示例(示例仅保留 1 条规则):
"record_filter": {
"enabled": false,
"exclude_if_any": [
{ "field": "domain", "regex": "(test|staging)", "case_sensitive": false }
]
}
scoring 示例(最简 weighted_average,且当前分数语义为“越低越好”):
"scoring": {
"enabled": true,
"strategy": "weighted_average",
"weighted_fields": [
{ "field": "avg_score", "weight": 1.0 }
],
"prefer_lower": true,
"within_hours": 24,
"tie_breakers": [
{ "field": "domain", "order": "asc" }
]
}
healthcheck 示例(当前默认 attempts=5):
"healthcheck": {
"enabled": false,
"attempts": 5,
"timeout_ms": 1800,
"port": 443,
"tls_verify": true
}
规则支持:
containsequalsregex说明:
record_filter/scoring引用未在record_mapping.field_map注册的字段时会 fail-fast;服务主流程、日志输出、runtime 文件写入逻辑保持不变。
python3 -m py_compile scripts/domain_updater.py
python3 -m py_compile scripts/update_vmess_links.py
python3 scripts/domain_updater.py --config config.json
cat runtime/current_domain.txt
cat runtime/current_domain.json
可选 HTTP 验证:
python3 -m http.server 8080 --directory runtime
curl http://127.0.0.1:8080/current_domain.json
git clone 到服务器(在仓库目录执行安装)origin 可用如果你采用“每台机器先手动保存 git 凭证”的流程,直接执行:
sudo bash scripts/install_debian.sh
默认行为:
sudo 执行前用户(SUDO_USER)1h--git-push 1)credential.helper storeruntime-state在服务用户下执行一次:
git config --global credential.helper store
git push origin runtime-state:runtime-state
首次输入用户名/密码(或 PAT)后,后续 systemd 可无交互 push。
关键点:保存凭证的用户必须和 service 的
User=一致。
sudo bash scripts/install_debian.sh \
--git-http-username <your-user> \
--git-http-token-file /root/.config/vmess-token \
--git-use-credential-store 1
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
成功时应看到:
committed runtime changes on runtime-state ...pushed to origin/runtime-statesudo bash scripts/install_debian.sh [options]
| 参数 | 说明 | 默认值 |
|---|---|---|
--user <name> |
指定 service 用户 | 当前 sudo 用户 |
--group <name> |
指定 service 用户组 | 当前 sudo 用户主组 |
--interval <value> |
定时周期(如 1h/5min) |
1h |
--git-push <0\|1> |
是否自动 push | 1 |
--git-push-remote <name> |
远程名 | origin |
--git-http-username <u> |
HTTPS 认证用户名 | git |
--git-http-token <t> |
HTTPS token(明文参数) | 空 |
--git-http-token-file <f> |
从文件读取 token | 空 |
--git-use-credential-store <0\|1> |
是否使用 credential.helper store |
1 |
--git-credentials-file <f> |
指定 credential store 文件路径 | 空(Git 默认) |
--no-install-deps |
跳过 apt 安装依赖 | 关闭 |
-h, --help |
查看帮助 | - |
说明:
--git-push 1 时,push 失败会返回非 0,systemd 任务标记失败(便于监控)。/etc/vmess-domain-rotator.env。install_debian.sh 会按安装参数动态写入 /etc/systemd/system/vmess-domain-rotator.service 和 /etc/systemd/system/vmess-domain-rotator.timer。仓库不再维护 systemd/* 静态模板文件。
service 示例(安装后实际内容会替换成你的参数):
[Unit]
Description=VMess Domain Rotator updater
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
User=<RUN_USER>
Group=<RUN_GROUP>
WorkingDirectory=<APP_DIR>
EnvironmentFile=-/etc/vmess-domain-rotator.env
UMask=0077
ExecStart=/bin/bash <APP_DIR>/scripts/run_update_and_commit.sh <APP_DIR>/config.json
timer 示例(OnUnitActiveSec 由 --interval 决定):
[Unit]
Description=Run VMess Domain Rotator every <INTERVAL>
[Timer]
OnBootSec=2min
OnUnitActiveSec=<INTERVAL>
AccuracySec=30s
Unit=vmess-domain-rotator.service
Persistent=true
[Install]
WantedBy=timers.target
scripts/run_update_and_commit.sh 的行为:
domain_updater.py 更新根目录 runtime/runtime-state 分支上次记录的域名比较runtime/ 下四个文件同步到 runtime-state worktree,再 commit--git-push 1 时要求 push 成功手动强制提交(忽略“域名相同”与“无变更”跳过逻辑):
bash scripts/run_update_and_commit.sh --force-commit config.json
# 或
GIT_FORCE_COMMIT=1 bash scripts/run_update_and_commit.sh config.json
说明:强制模式会使用 manual: 前缀的提交信息(包含域名和更新时间);若内容无变化,会创建 empty commit 后继续按配置 push。
sudo systemctl status vmess-domain-rotator.timer
sudo systemctl status vmess-domain-rotator.service
sudo systemctl start vmess-domain-rotator.service
sudo systemctl restart vmess-domain-rotator.timer
sudo journalctl -u vmess-domain-rotator.service -n 200 --no-pager
sudo journalctl -u vmess-domain-rotator.service -f
git log runtime-state --oneline -n 20
sudo bash scripts/uninstall_debian.sh
保留认证/env 文件:
sudo bash scripts/uninstall_debian.sh --keep-auth-files
python3 scripts/update_vmess_links.py \
--input ./nodes.txt \
--output ./nodes.updated.txt \
--domain-file ./runtime/current_domain.txt
仅替换匹配名称(ps)的节点:
python3 scripts/update_vmess_links.py \
--input ./nodes.txt \
--output ./nodes.updated.txt \
--domain-file ./runtime/current_domain.txt \
--name-regex "(argo|cf|vm)"
fatal: could not read Username ... terminal prompts disabledcredential.helper store 为明文存储,建议仅在可控服务器使用。runtime/state.json 需要持久化,保障 fallback 能用。