|
@@ -1,17 +1,48 @@
|
|
|
# vmess-domain-rotator
|
|
# vmess-domain-rotator
|
|
|
|
|
|
|
|
-This repo provides a first working version of an automated pipeline:
|
|
|
|
|
|
|
+一个用于 **自动获取优选域名**、写入 `runtime/` 运行时文件,并按计划将运行时变更提交到 `runtime-state` 分支的工具。
|
|
|
|
|
|
|
|
-1. Pull preferred domains from an API (like vps789).
|
|
|
|
|
-2. Validate and optionally health-check candidates.
|
|
|
|
|
-3. Pick the best domain automatically.
|
|
|
|
|
-4. Export runtime files for Sub-Store and V2Ray integration.
|
|
|
|
|
|
|
+---
|
|
|
|
|
|
|
|
-## Quick start
|
|
|
|
|
|
|
+## 1. 功能概览
|
|
|
|
|
|
|
|
-1. Edit `config.json` directly (single runtime config file).
|
|
|
|
|
|
|
+本项目主要完成以下流程:
|
|
|
|
|
|
|
|
-For your sample response (`data.good[].ip`), parser config can be:
|
|
|
|
|
|
|
+1. 从 API 拉取候选域名/IP
|
|
|
|
|
+2. 解析并过滤候选结果
|
|
|
|
|
+3. 按规则打分/选择最终域名
|
|
|
|
|
+4. 写入运行时文件到 `runtime/`
|
|
|
|
|
+5. (可选)将运行时变更自动提交并 push 到 `runtime-state`
|
|
|
|
|
+
|
|
|
|
|
+核心脚本:
|
|
|
|
|
+
|
|
|
|
|
+- `scripts/domain_updater.py`:执行域名拉取、选择与写文件
|
|
|
|
|
+- `scripts/run_update_and_commit.sh`:执行 updater + git 提交/推送
|
|
|
|
|
+- `scripts/install_debian.sh`:Debian 下安装 systemd service + timer
|
|
|
|
|
+- `scripts/uninstall_debian.sh`:卸载 systemd 与认证环境文件
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 2. 运行产物
|
|
|
|
|
+
|
|
|
|
|
+默认写入仓库根目录 `runtime/`:
|
|
|
|
|
+
|
|
|
|
|
+- `runtime/current_domain.txt`:当前域名(纯文本)
|
|
|
|
|
+- `runtime/current_domain.json`:当前结果 JSON
|
|
|
|
|
+- `runtime/state.json`:状态文件(含 `last_good_domain`)
|
|
|
|
|
+- `runtime/substore_vars.json`:给外部系统消费的变量
|
|
|
|
|
+
|
|
|
|
|
+> 注意:`domain_updater.py` 现在会按 `--config` 文件所在目录解析 `output.runtime_dir`(默认 `./runtime`),避免误写到 `scripts/runtime/`。
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 3. 本地快速开始
|
|
|
|
|
+
|
|
|
|
|
+### 3.1 配置
|
|
|
|
|
+
|
|
|
|
|
+编辑 `config.json`。
|
|
|
|
|
+
|
|
|
|
|
+典型解析路径(如 API 返回 `data.good[].ip`):
|
|
|
|
|
|
|
|
```json
|
|
```json
|
|
|
"parser": {
|
|
"parser": {
|
|
@@ -21,213 +52,218 @@ For your sample response (`data.good[].ip`), parser config can be:
|
|
|
}
|
|
}
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-For vps789 Top20 ranking, if you want "directly use first ranked domain":
|
|
|
|
|
-
|
|
|
|
|
-```json
|
|
|
|
|
-"scoring": {
|
|
|
|
|
- "enabled": true,
|
|
|
|
|
- "records_path": "data.good[]",
|
|
|
|
|
- "ip_field": "ip",
|
|
|
|
|
- "created_time_field": "createdTime",
|
|
|
|
|
- "within_hours": 24,
|
|
|
|
|
- "use_api_order": true
|
|
|
|
|
-}
|
|
|
|
|
-```
|
|
|
|
|
-
|
|
|
|
|
-Then set:
|
|
|
|
|
|
|
+### 3.2 语法检查
|
|
|
|
|
|
|
|
-```json
|
|
|
|
|
-"healthcheck": { "enabled": false }
|
|
|
|
|
|
|
+```bash
|
|
|
|
|
+python3 -m py_compile scripts/domain_updater.py
|
|
|
|
|
+python3 -m py_compile scripts/update_vmess_links.py
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-2. Run once:
|
|
|
|
|
|
|
+### 3.3 运行一次
|
|
|
|
|
|
|
|
```bash
|
|
```bash
|
|
|
python3 scripts/domain_updater.py --config config.json
|
|
python3 scripts/domain_updater.py --config config.json
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-3. Check output files:
|
|
|
|
|
|
|
+### 3.4 本地查看结果
|
|
|
|
|
|
|
|
-- `runtime/current_domain.txt`
|
|
|
|
|
-- `runtime/current_domain.json`
|
|
|
|
|
-- `runtime/state.json`
|
|
|
|
|
-
|
|
|
|
|
-## What the script exports
|
|
|
|
|
|
|
+```bash
|
|
|
|
|
+cat runtime/current_domain.txt
|
|
|
|
|
+cat runtime/current_domain.json
|
|
|
|
|
+```
|
|
|
|
|
|
|
|
-- `current_domain.txt`: plain text domain.
|
|
|
|
|
-- `current_domain.json`: machine-readable payload:
|
|
|
|
|
|
|
+可选 HTTP 验证:
|
|
|
|
|
|
|
|
-```json
|
|
|
|
|
-{
|
|
|
|
|
- "domain": "best.example.com",
|
|
|
|
|
- "updated_at": "2026-04-13T07:00:00Z",
|
|
|
|
|
- "status": "ok",
|
|
|
|
|
- "source_count": 15,
|
|
|
|
|
- "checked_count": 10
|
|
|
|
|
-}
|
|
|
|
|
|
|
+```bash
|
|
|
|
|
+python3 -m http.server 8080 --directory runtime
|
|
|
|
|
+curl http://127.0.0.1:8080/current_domain.json
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-- `state.json`: includes `last_good_domain` for automatic fallback.
|
|
|
|
|
|
|
+---
|
|
|
|
|
|
|
|
-If you need Sub-Store to fetch these files over HTTP, you can expose `runtime/` via nginx or caddy.
|
|
|
|
|
|
|
+## 4. Debian 一键部署(完整教程)
|
|
|
|
|
|
|
|
-## How to connect with Sub-Store
|
|
|
|
|
|
|
+## 4.1 前置条件
|
|
|
|
|
|
|
|
-Two practical modes:
|
|
|
|
|
|
|
+- Debian/Ubuntu
|
|
|
|
|
+- 项目已 `git clone` 到服务器(在仓库目录执行安装)
|
|
|
|
|
+- 远程仓库 `origin` 可用
|
|
|
|
|
+- 用于运行服务的用户有仓库读写权限
|
|
|
|
|
|
|
|
-1. **Recommended**: run updater externally and let Sub-Store operator fetch `current_domain.json`.
|
|
|
|
|
-2. Keep Sub-Store static and update V2Ray template directly (token replacement).
|
|
|
|
|
|
|
+---
|
|
|
|
|
|
|
|
-`substore/operator_template.js` is a starter operator script showing how to replace VMess `server` fields by regex match on node names.
|
|
|
|
|
|
|
+### 4.2 推荐方案(不传参数)
|
|
|
|
|
|
|
|
-Minimal smoke test (local):
|
|
|
|
|
|
|
+如果你采用“每台机器先手动保存 git 凭证”的流程,直接执行:
|
|
|
|
|
|
|
|
```bash
|
|
```bash
|
|
|
-python3 -m http.server 8080 --directory runtime
|
|
|
|
|
|
|
+sudo bash scripts/install_debian.sh
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-Then test:
|
|
|
|
|
|
|
+默认行为:
|
|
|
|
|
|
|
|
-```bash
|
|
|
|
|
-curl http://127.0.0.1:8080/current_domain.json
|
|
|
|
|
-```
|
|
|
|
|
|
|
+- 服务用户:当前 `sudo` 执行前用户(`SUDO_USER`)
|
|
|
|
|
+- 定时间隔:`1h`
|
|
|
|
|
+- 自动 push:开启(`--git-push 1`)
|
|
|
|
|
+- 认证模式:`credential.helper store`
|
|
|
|
|
+- 推送分支:`runtime-state`
|
|
|
|
|
|
|
|
-## How to connect with V2Ray
|
|
|
|
|
|
|
+---
|
|
|
|
|
|
|
|
-If you maintain a template config (containing `__AUTO_DOMAIN__` token), this script can render a real config file with the selected domain.
|
|
|
|
|
|
|
+### 4.3 Git 凭证(无交互)配置建议
|
|
|
|
|
|
|
|
-Then reload service:
|
|
|
|
|
|
|
+#### 方式 A:手动存凭证(你当前采用的方式)
|
|
|
|
|
+
|
|
|
|
|
+在**服务用户**下执行一次:
|
|
|
|
|
|
|
|
```bash
|
|
```bash
|
|
|
-systemctl reload v2ray
|
|
|
|
|
|
|
+git config --global credential.helper store
|
|
|
|
|
+git push origin runtime-state:runtime-state
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-## Update Base64 VMess links
|
|
|
|
|
|
|
+首次输入用户名/密码(或 PAT)后,后续 systemd 可无交互 push。
|
|
|
|
|
+
|
|
|
|
|
+> 关键点:保存凭证的用户必须和 service 的 `User=` 一致。
|
|
|
|
|
|
|
|
-If your node list uses `vmess://<base64-json>`, use:
|
|
|
|
|
|
|
+#### 方式 B:安装脚本带 token(可选)
|
|
|
|
|
|
|
|
```bash
|
|
```bash
|
|
|
-python3 scripts/update_vmess_links.py \
|
|
|
|
|
- --input ./nodes.txt \
|
|
|
|
|
- --output ./nodes.updated.txt \
|
|
|
|
|
- --domain-file ./runtime/current_domain.txt
|
|
|
|
|
|
|
+sudo bash scripts/install_debian.sh \
|
|
|
|
|
+ --git-http-username <your-user> \
|
|
|
|
|
+ --git-http-token-file /root/.config/vmess-token \
|
|
|
|
|
+ --git-use-credential-store 1
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-Only update specific node names (`ps`) by regex:
|
|
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+### 4.4 安装后验证
|
|
|
|
|
|
|
|
```bash
|
|
```bash
|
|
|
-python3 scripts/update_vmess_links.py \
|
|
|
|
|
- --input ./nodes.txt \
|
|
|
|
|
- --output ./nodes.updated.txt \
|
|
|
|
|
- --domain-file ./runtime/current_domain.txt \
|
|
|
|
|
- --name-regex "(argo|cf|vm)"
|
|
|
|
|
-```
|
|
|
|
|
|
|
+sudo systemctl status vmess-domain-rotator.timer
|
|
|
|
|
+sudo systemctl status vmess-domain-rotator.service
|
|
|
|
|
|
|
|
-If the whole subscription file is itself base64-encoded, add:
|
|
|
|
|
|
|
+# 手动触发一次
|
|
|
|
|
+sudo systemctl start vmess-domain-rotator.service
|
|
|
|
|
|
|
|
-```bash
|
|
|
|
|
---subscription-base64
|
|
|
|
|
|
|
+# 看日志
|
|
|
|
|
+sudo journalctl -u vmess-domain-rotator.service -n 120 --no-pager
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-## Scheduling
|
|
|
|
|
|
|
+成功时应看到:
|
|
|
|
|
+
|
|
|
|
|
+- updater 输出 JSON
|
|
|
|
|
+- `committed runtime changes on runtime-state ...`
|
|
|
|
|
+- `pushed to origin/runtime-state`
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
|
|
|
-### Cron
|
|
|
|
|
|
|
+## 5. install_debian.sh 参数说明
|
|
|
|
|
|
|
|
-```cron
|
|
|
|
|
-0 * * * * /bin/bash /opt/vmess-domain-rotator/scripts/run_update_and_commit.sh /opt/vmess-domain-rotator/config.json >> /var/log/vmess-domain-rotator.log 2>&1
|
|
|
|
|
|
|
+```bash
|
|
|
|
|
+sudo bash scripts/install_debian.sh [options]
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-### systemd timer
|
|
|
|
|
|
|
+| 参数 | 说明 | 默认值 |
|
|
|
|
|
+|---|---|---|
|
|
|
|
|
+| `--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` | 查看帮助 | - |
|
|
|
|
|
|
|
|
-Use files under `systemd/` and adjust paths/user.
|
|
|
|
|
-Default timer interval in this repo is `1h`.
|
|
|
|
|
|
|
+说明:
|
|
|
|
|
|
|
|
-### Debian install/uninstall scripts
|
|
|
|
|
|
|
+- `--git-push 1` 时,push 失败会返回非 0,systemd 任务标记失败(便于监控)。
|
|
|
|
|
+- 安装会写入环境文件:`/etc/vmess-domain-rotator.env`。
|
|
|
|
|
|
|
|
-Install on a Debian server (creates systemd service+timer):
|
|
|
|
|
|
|
+---
|
|
|
|
|
|
|
|
-```bash
|
|
|
|
|
-sudo bash scripts/install_debian.sh
|
|
|
|
|
-```
|
|
|
|
|
|
|
+## 6. 自动提交/推送逻辑说明
|
|
|
|
|
|
|
|
-This installer is in-place only (service runs from current git clone path). Runtime updates are committed to `runtime-state` and when push is enabled (`--git-push 1`, default), push failure is treated as a service failure.
|
|
|
|
|
|
|
+`scripts/run_update_and_commit.sh` 的行为:
|
|
|
|
|
|
|
|
-Non-interactive push/auth options:
|
|
|
|
|
|
|
+1. 运行 `domain_updater.py` 更新根目录 `runtime/`
|
|
|
|
|
+2. 切到(或创建)`runtime-state` worktree
|
|
|
|
|
+3. 将 `runtime/` 下四个文件同步到 `runtime-state` worktree
|
|
|
|
|
+4. 仅当 **runtime-state 分支内容有差异** 时才 commit
|
|
|
|
|
+5. `--git-push 1` 时要求 push 成功
|
|
|
|
|
|
|
|
-```bash
|
|
|
|
|
-# Disable push completely (only local runtime-state commits)
|
|
|
|
|
-sudo bash scripts/install_debian.sh --git-push 0
|
|
|
|
|
|
|
+即:不再只看 main 分支当前文件是否变化,而是看 `runtime-state` 目标内容是否有变化。
|
|
|
|
|
|
|
|
-# Recommended: credential.helper store (same style as manual git config --global credential.helper store)
|
|
|
|
|
-sudo bash scripts/install_debian.sh \
|
|
|
|
|
- --user aurora --group aurora \
|
|
|
|
|
- --git-http-username aurora \
|
|
|
|
|
- --git-http-token-file /root/.config/vmess-token \
|
|
|
|
|
- --git-use-credential-store 1
|
|
|
|
|
|
|
+---
|
|
|
|
|
|
|
|
-# Optional: set explicit credential store file
|
|
|
|
|
-sudo bash scripts/install_debian.sh \
|
|
|
|
|
- --user aurora --group aurora \
|
|
|
|
|
- --git-http-username aurora \
|
|
|
|
|
- --git-http-token-file /root/.config/vmess-token \
|
|
|
|
|
- --git-use-credential-store 1 \
|
|
|
|
|
- --git-credentials-file /home/aurora/.git-credentials
|
|
|
|
|
-```
|
|
|
|
|
|
|
+## 7. 常用运维命令
|
|
|
|
|
|
|
|
-Installer behavior for auth:
|
|
|
|
|
-- With `--git-use-credential-store 1`, installer configures service user global git credential helper and writes credentials via `git credential approve`.
|
|
|
|
|
-- With `--git-use-credential-store 0`, installer stores token at `/var/lib/vmess-domain-rotator/git_http_token` and service uses header-based auth.
|
|
|
|
|
-- Service environment is written to `/etc/vmess-domain-rotator.env`.
|
|
|
|
|
|
|
+### 7.1 service / timer
|
|
|
|
|
|
|
|
-Push behavior:
|
|
|
|
|
-- `--git-push 1` (default): commit + push are required; push failure exits non-zero so systemd marks run failed.
|
|
|
|
|
-- `--git-push 0`: only local runtime-state commit is attempted, push skipped.
|
|
|
|
|
|
|
+```bash
|
|
|
|
|
+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
|
|
|
|
|
+```
|
|
|
|
|
|
|
|
-Uninstall:
|
|
|
|
|
|
|
+### 7.2 日志
|
|
|
|
|
|
|
|
```bash
|
|
```bash
|
|
|
-sudo bash scripts/uninstall_debian.sh
|
|
|
|
|
|
|
+sudo journalctl -u vmess-domain-rotator.service -n 200 --no-pager
|
|
|
|
|
+sudo journalctl -u vmess-domain-rotator.service -f
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-Keep auth/env files during uninstall:
|
|
|
|
|
|
|
+### 7.3 查看 runtime-state 提交
|
|
|
|
|
|
|
|
```bash
|
|
```bash
|
|
|
-sudo bash scripts/uninstall_debian.sh --keep-auth-files
|
|
|
|
|
|
|
+git log runtime-state --oneline -n 20
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-Useful options:
|
|
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 8. 卸载
|
|
|
|
|
|
|
|
```bash
|
|
```bash
|
|
|
-sudo bash scripts/install_debian.sh --user aurora --group aurora --interval 5min
|
|
|
|
|
-sudo bash scripts/install_debian.sh --git-push-remote origin
|
|
|
|
|
|
|
+sudo bash scripts/uninstall_debian.sh
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-## Config notes
|
|
|
|
|
|
|
+保留认证/env 文件:
|
|
|
|
|
|
|
|
-- API response formats differ. Use one of:
|
|
|
|
|
- - `parser.json_paths` (preferred)
|
|
|
|
|
- - `parser.regex` fallback
|
|
|
|
|
-- If API has occasional bad results, keep `healthcheck.enabled=true`.
|
|
|
|
|
-- If API may return IPv4 addresses, consider `healthcheck.tls_verify=false`.
|
|
|
|
|
-- If all checks fail, script falls back to last known good domain.
|
|
|
|
|
|
|
+```bash
|
|
|
|
|
+sudo bash scripts/uninstall_debian.sh --keep-auth-files
|
|
|
|
|
+```
|
|
|
|
|
|
|
|
-## About Sub-Store "config file location"
|
|
|
|
|
|
|
+---
|
|
|
|
|
|
|
|
-If you use Sub-Store web UI, rules are usually stored in backend data storage (sqlite/json), not a simple editable config file.
|
|
|
|
|
|
|
+## 9. VMess 链接批量替换(可选)
|
|
|
|
|
|
|
|
-Common deployment cases:
|
|
|
|
|
|
|
+```bash
|
|
|
|
|
+python3 scripts/update_vmess_links.py \
|
|
|
|
|
+ --input ./nodes.txt \
|
|
|
|
|
+ --output ./nodes.updated.txt \
|
|
|
|
|
+ --domain-file ./runtime/current_domain.txt
|
|
|
|
|
+```
|
|
|
|
|
|
|
|
-- Docker: check mounted volume path, then back up that volume.
|
|
|
|
|
-- Node/PM2: check app directory `data/` or database file.
|
|
|
|
|
|
|
+仅替换匹配名称(`ps`)的节点:
|
|
|
|
|
|
|
|
-In practice, you can avoid touching backend db files directly:
|
|
|
|
|
|
|
+```bash
|
|
|
|
|
+python3 scripts/update_vmess_links.py \
|
|
|
|
|
+ --input ./nodes.txt \
|
|
|
|
|
+ --output ./nodes.updated.txt \
|
|
|
|
|
+ --domain-file ./runtime/current_domain.txt \
|
|
|
|
|
+ --name-regex "(argo|cf|vm)"
|
|
|
|
|
+```
|
|
|
|
|
|
|
|
-1. Keep your node logic in Sub-Store operator script (web UI).
|
|
|
|
|
-2. Let operator fetch `current_domain.json` from this project.
|
|
|
|
|
-3. Dynamic replacement happens at subscription processing time.
|
|
|
|
|
|
|
+---
|
|
|
|
|
|
|
|
-## Security and reliability
|
|
|
|
|
|
|
+## 10. 注意事项
|
|
|
|
|
|
|
|
-- Do not commit API tokens.
|
|
|
|
|
-- Use reverse proxy auth if exposing `current_domain.json` publicly.
|
|
|
|
|
-- Keep `runtime/state.json` persisted (for fallback).
|
|
|
|
|
|
|
+1. **服务用户与 git 凭证用户必须一致**,否则会出现:
|
|
|
|
|
+ - `fatal: could not read Username ... terminal prompts disabled`
|
|
|
|
|
+2. `credential.helper store` 为明文存储,建议仅在可控服务器使用。
|
|
|
|
|
+3. 不要把 token 提交进仓库。
|
|
|
|
|
+4. `runtime/state.json` 需要持久化,保障 fallback 能用。
|