Ver código fonte

fix: server interval to 30 min

Dew-OF-Aurora 3 semanas atrás
pai
commit
944f6f5dd1
4 arquivos alterados com 199 adições e 23 exclusões
  1. 179 12
      README.md
  2. 4 4
      config_router.conf
  3. 2 2
      scripts/install_debian.sh
  4. 14 5
      scripts/router_local_update.sh

+ 179 - 12
README.md

@@ -79,28 +79,155 @@ 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
 ```
 
-### 3.3 维护命令
+### 3.3 安装与部署(Debian/Ubuntu systemd)
+
+为了在服务器上实现无人值守的定时域名更新与自动 Git 提交,本项目提供了一套完整的 `systemd` 服务安装脚本。
+
+#### 3.3.1 系统准备与要求
+- **操作系统**:Debian / Ubuntu / Armbian 等基于 Debian 的发行版。
+- **系统工具**:`systemd`(系统服务管理)、`runuser`(安全切换用户执行)。
+- **软件依赖**:Python 3、Git、`ca-certificates`(若缺失,安装脚本默认会通过 `apt-get` 自动补全)。
+
+#### 3.3.2 安装脚本参数详解
+
+你可以使用 `sudo bash scripts/install_debian.sh [options]` 进行灵活安装:
+
+| 参数选项 | 默认值 | 说明 |
+| :--- | :--- | :--- |
+| `--config <path>` | `config.server.json` | 配置文件路径(若为相对路径,则相对于仓库根目录) |
+| `--interval <value>` | `30min` | 定时器执行间隔,例如 `1h`、`30min`、`10s` 等 |
+| `--user <name>` | 当前 `sudo` 用户 | 运行 systemd 服务的非 root 系统用户 |
+| `--group <name>` | 当前 `sudo` 用户组 | 运行 systemd 服务的系统用户组 |
+| `--git-push <0\|1>` | `1` | 选出新域名并 commit 后,是否自动推送(`git push`)到远程仓库 |
+| `--git-push-remote <name>` | `origin` | 推送的 Git 远程仓库名称 |
+| `--git-http-username <u>` | `git` | 远程 Git 仓库的 HTTPS 认证用户名 |
+| `--git-http-token <token>` | 空 | 远程 Git 仓库的 HTTPS 访问令牌(用于非交互式免密推送) |
+| `--git-http-token-file <path>` | 空 | 从指定文件中读取 HTTPS 访问令牌,避免命令行泄露敏感信息 |
+| `--git-use-credential-store <0\|1>` | `1` | 是否使用 Git 凭据辅助存储(`credential.helper store`)持久化 Token |
+| `--git-credentials-file <path>` | 空 | 自定义凭据存储文件的路径(若不指定,默认保存在服务用户家目录下) |
+| `--no-install-deps` | 否 | 跳过 `apt-get` 依赖包检测与自动安装 |
+| `-h, --help` | - | 显示帮助信息 |
+
+> [!IMPORTANT]
+> **关于 Git 自动推送(Push)与凭据认证**
+> 1. **HTTPS 认证(推荐使用 Token)**:指定 `--git-http-token` 或 `--git-http-token-file`。安装脚本会自动启动 `git credential approve` 为指定的运行用户配置全局凭据,且所有 Token 信息都会以安全权限(`600`)保存在独立配置文件中,杜绝安全隐患。
+> 2. **SSH 认证**:如果远程仓库使用 SSH 地址(例如 `git@github.com:...`),只需在安装时指定 `--git-use-credential-store 0`。只要确保配置的 `--user` 用户的 SSH 密钥已被授权到远程 Git 平台即可。
+> 3. **安全隔离**:服务不允许以 `root` 用户身份保存 Git Token。若使用 Token 认证,必须指定非 root 用户(默认即为执行 `sudo` 的普通用户)。
+> 4. **Git 安全目录**:安装脚本会自动为服务运行用户注入 `git config --global --add safe.directory` 配置,彻底避免 systemd 执行时因目录所有权引起的 Git 安全阻拦错误。
+
+#### 3.3.3 快速安装示例
+
+**示例 1:最简安装(每 30 分钟自动运行,使用默认配置,支持 Git 推送)**
+```bash
+sudo bash scripts/install_debian.sh
+```
 
+**示例 2:自定义时间间隔,并通过文件安全读取 GitHub/GitLab 访问令牌**
 ```bash
-# 语法检查
-env PYTHONPYCACHEPREFIX=/tmp/pycache python3 -m py_compile scripts/domain_updater.py
-bash -n scripts/run_update_and_commit.sh
+sudo bash scripts/install_debian.sh --interval 10min --git-http-username aurora --git-http-token-file /home/aurora/.github_token
+```
 
-# 查看解析后的输出路径
-python3 scripts/domain_updater.py --config config.server.json --print-output-settings
+**示例 3:纯本地运行,不推送到远程仓库**
+```bash
+sudo bash scripts/install_debian.sh --git-push 0
+```
+
+---
+
+### 3.4 卸载服务
+
+如果你需要卸载 systemd 定时任务和服务,可以使用自带的卸载脚本。该脚本会自动停止正在运行的定时器与服务,移除系统 unit 文件,清理 Git 全局安全路径配置,并重载 `systemd`。
+
+```bash
+sudo bash scripts/uninstall_debian.sh [options]
+```
 
-# systemd(Debian/Ubuntu)
-sudo bash scripts/install_debian.sh --config config.server.json
+**参数选项:**
+- `--keep-auth-files`:保留安装时生成的环境配置文件(`/etc/vmess-domain-rotator.env`)与保存凭据的安全目录(`/var/lib/vmess-domain-rotator`)。若计划稍后重新安装,建议加上此参数。
+- `--service-name <name>`:指定要卸载的服务基名(默认为 `vmess-domain-rotator`)。
+
+**快速卸载示例:**
+```bash
+# 彻底卸载(默认清除所有关联的 Token 与配置文件,保留 git 仓库代码)
+sudo bash scripts/uninstall_debian.sh
+
+# 卸载服务但保留认证凭据
+sudo bash scripts/uninstall_debian.sh --keep-auth-files
+```
+
+---
+
+### 3.5 常用命令与日常维护
+
+部署完成后,你可以通过以下命令对服务进行管理和排错:
+
+```bash
+# 查看定时器状态与下一次执行时间
 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
 
-# 卸载
-sudo bash scripts/uninstall_debian.sh
+# 实时查看运行日志
+sudo journalctl -u vmess-domain-rotator.service -f --no-pager
+
+# 查看最近 100 行日志
+sudo journalctl -u vmess-domain-rotator.service -n 100 --no-pager
+
+# 语法与配置预检
+env PYTHONPYCACHEPREFIX=/tmp/pycache python3 -m py_compile scripts/domain_updater.py
+bash -n scripts/run_update_and_commit.sh
+
+# 检查当前配置解析出的实际输出路径
+python3 scripts/domain_updater.py --config config.server.json --print-output-settings
+
+# 手动强制提交当前域名(即便域名没有发生变化,也会生成 commit 并推送到 remote)
+sudo -u aurora bash scripts/run_update_and_commit.sh --force-commit config.server.json
 ```
 
-### 3.4 日志格式(服务器模式)
+---
+
+### 3.6 核心规则:筛选与评分策略
+
+服务器模式(API)采用结构化的过滤与权衡评分机制,保证筛选出的域名兼顾**极低的延迟**与**极低的丢包率**。
+
+#### 3.6.1 API 字段转换映射 (`record_mapping`)
+通过 `config.server.json` 中的 `record_mapping` 块,可以将任意 API 响应中的自定义字段映射为标准字段。目前已映射的标准字段包括:
+- `domain`:物理域名/IP。
+- `created_at`:记录创建时间(支持时区与多种格式解析)。
+- `yd_latency` / `yd_pkg_lost_rate`:移动延迟 / 移动丢包率。
+- `dx_latency` / `dx_pkg_lost_rate`:电信延迟 / 电信丢包率。
+- `lt_latency` / `lt_pkg_lost_rate`:联通延迟 / 联通丢包率。
+- `avg_latency` / `avg_pkg_lost_rate`:三网平均延迟 / 平均丢包率。
+
+#### 3.6.2 数据筛选过滤器 (`record_filter` 与 `domain_filter`)
+- **API 记录过滤 (`record_filter`)**:在解析前排除包含特定语义的字段。例如,默认过滤掉 `host_provider` 为 "CF优选IP" 的记录,或排除特定敏感域名。
+- **域名规则过滤 (`domain_filter`)**:根据正则表达式排除不合格的物理格式。例如,默认使用正则排除直接为 IPv4 格式的记录,只保留纯域名。
+
+#### 3.6.3 评分排序策略 (`scoring`)
+评分机制(以 `weighted_average` 策略为例)将对剩余的候选域名进行加权评分:
+- **加权字段设置 (`weighted_fields`)**:
+  在默认的 `config.server.json` 中,为了优化中国移动线路的访问表现,配置了以下加权项:
+  - `yd_latency` (权重: `1.0`)
+  - `yd_pkg_lost_rate` (权重: `10.0`)
+- **评分计算方式**:
+  $$\text{Score} = \frac{\sum (\text{Field Value} \times \text{Weight})}{\sum \text{Weights}}$$
+- **优先级方向 (`prefer_lower`)**:设置为 `true`,分值越低(延迟越低、丢包率越少)则排名越靠前。
+- **时效性过滤 (`within_hours`)**:自动过滤掉创建时间超过 24 小时的陈旧测试记录。
+- **决胜规则 (`tie_breakers`)**:当评分相同时,支持按备用字段(如 `created_at` 降序、`domain` 升序)进行决胜排序,保证排序的绝对确定性。
+
+#### 3.6.4 备用容灾设计(Fallback)
+如果 API 请求超时、解析失败或过滤后无可用域名:
+1. 更新器会读取 `runtime/state.json` 中上一次持久化保存的 `last_good_domain`。
+2. 自动降级回退使用该域名,确保下游服务不会因为短暂的网络扰动而中断。
+3. 状态标记为 `error_use_last_good`,调度脚本捕获后会以 `chore(fallback):` 作为前缀提交,方便管理员追溯。
+
+---
+
+### 3.7 日志格式(服务器模式)
 
 `scripts/run_update_and_commit.sh`、`scripts/install_debian.sh`、`scripts/uninstall_debian.sh` 的日志统一为:
 
@@ -274,6 +401,46 @@ curl http://127.0.0.1:8080/current_ip.txt
 
 ---
 
+### 5.8 [最佳实践] 延长路由器闪存寿命(防擦写优化)
+
+> [!WARNING]
+> **为什么要配置防擦写优化?**
+> 路由器的 `/jffs` 目录是位于 NAND/NOR Flash 物理闪存介质上的。本项目默认每小时执行一次本地 `cfst` 测速并生成 `result.csv`。如果将这些临时文件直接写入 `/jffs`,**长期高频擦写将严重缩短路由器硬件闪存的寿命**。
+
+本项目已经完美支持了**绝对路径智能解析与动静分离存储**方案。你可以将所有高频读写的临时文件和运行期数据全部重定向至系统的 **RAM 内存临时文件系统(`/tmp`)**,而仅将最关键的初始化与容灾文件(`state.json`)保存在闪存上。
+
+#### 5.8.1 防擦写推荐配置
+
+修改路由器上的 `config_router.conf`,将高频写操作的目录与文件路径配置如下:
+
+```bash
+# 1. 测速工作区与输入文件保存在 flash 上(只读性质)
+CFST_WORK_DIR="/jffs/vmess/cfst"
+CFST_BIN="./cfst"
+CFST_IP_FILE="ip.txt"
+
+# 2. 【核心优化】测速输出 csv 定向到内存系统(/tmp),不磨损硬件!
+CFST_RESULT_FILE="/tmp/vmess_result.csv"
+
+# 3. 【核心优化】运行期数据目录全部指向内存,速度飞快且零硬件磨损
+RUNTIME_DIR="/tmp/vmess_runtime"
+VALUE_TEXT_FILE="current_ip.txt"
+VALUE_JSON_FILE="current_ip.json"
+EXPORT_VARS_FILE="substore_vars.json"
+
+# 4. 【容灾持久化】将上次可用值 state.json 独立保存在物理闪存中,保证重启后不丢失
+# 因为只有在真正检测到 IP 变化并写入成功时才会写一次 Flash,写入频率极低(通常几天或几周写一次),安全无虞。
+STATE_FILE="/jffs/vmess/state.json"
+```
+
+#### 5.8.2 原理解析与效果
+1. **自动建目录**:在 RAM 中,`/tmp/vmess_runtime` 会在每次开机或定时器运行 `router_local_update.sh` 时,通过 `mkdir -p` 自动创建,无需手动干预。
+2. **零闪存磨损**:在测速时,`cfst` 会将大量的下载速度数据、中间进度及最终的 `vmess_result.csv` 写入 RAM 内存,彻底消除闪存介质每小时擦写几百 KB 的问题。
+3. **极速读取**:BusyBox `httpd` 将直接挂载 `/tmp/vmess_runtime` 目录来服务 Sub-Store。因为数据常驻内存,HTTP 响应速度可以提升至微秒级。
+4. **断电容灾存留**:如果路由器断电重启,内存中的 `/tmp` 随之清空。但由于我们把备用状态 `state.json` 单独放回了物理闪存 `/jffs/vmess/state.json`,下一次定时器启动时,如果暂时无法连接网络或测速报错,脚本依然能成功从 Flash 读回上次可用的 fallback IP 并完美恢复服务。
+
+---
+
 ## 6. Sub-Store 脚本模式说明
 
 `substore/operator_template.js` 支持:

+ 4 - 4
config_router.conf

@@ -1,7 +1,7 @@
-CFST_WORK_DIR="./cfst"
+CFST_WORK_DIR="/jffs/vmess/cfst"
 CFST_BIN="./cfst"
 CFST_IP_FILE="ip.txt"
-CFST_RESULT_FILE="result.csv"
+CFST_RESULT_FILE="/tmp/vmess_result.csv"
 CFST_DISPLAY_COUNT="10"
 CFST_THREADS=""
 CFST_TEST_COUNT=""
@@ -22,10 +22,10 @@ CFST_DEBUG="0"
 CFST_SKIP_RUN="0"
 
 TOP_N="3"
-RUNTIME_DIR="./cfip_runtime"
+RUNTIME_DIR="/tmp/vmess_runtime"
 VALUE_TEXT_FILE="current_ip.txt"
 VALUE_JSON_FILE="current_ip.json"
-STATE_FILE="state.json"
+STATE_FILE="/jffs/vmess/state.json"
 EXPORT_VARS_FILE="substore_vars.json"
 VALUE_JSON_KEY="ip"
 STATE_LAST_GOOD_KEY="last_good_ip"

+ 2 - 2
scripts/install_debian.sh

@@ -19,7 +19,7 @@ RUN_GROUP=""
 RUN_USER_SET="0"
 RUN_GROUP_SET="0"
 RUN_HOME=""
-INTERVAL="1h"
+INTERVAL="30min"
 INSTALL_DEPS="1"
 CONFIG_PATH=""
 GIT_PUSH_ENABLED="1"
@@ -42,7 +42,7 @@ Default behavior:
 Options:
  --user <name>                  Service user (default: current sudo user)
  --group <name>                 Service group (default: current sudo user's group)
- --interval <value>             Timer interval, e.g. 1h/10min (default: 1h)
+ --interval <value>             Timer interval, e.g. 1h/30min (default: 30min)
  --config <path>                Config file path (default: <repo>/config.server.json)
  --git-push <0|1>               Enable/disable push to remote (default: 1)
  --git-push-remote <name>       Remote name for push (default: origin)

+ 14 - 5
scripts/router_local_update.sh

@@ -60,12 +60,21 @@ VALUE_JSON_KEY=${VALUE_JSON_KEY:-ip}
 STATE_LAST_GOOD_KEY=${STATE_LAST_GOOD_KEY:-last_good_ip}
 EXPORT_VALUE_KEY=${EXPORT_VALUE_KEY:-AUTO_CFIP}
 
-CURRENT_TEXT_PATH="$RUNTIME_DIR/$VALUE_TEXT_FILE"
-CURRENT_JSON_PATH="$RUNTIME_DIR/$VALUE_JSON_FILE"
-STATE_PATH="$RUNTIME_DIR/$STATE_FILE"
-EXPORT_VARS_PATH="$RUNTIME_DIR/$EXPORT_VARS_FILE"
+resolve_path() {
+  _p="$1"
+  _base_dir="$2"
+  case "$_p" in
+    /*) printf '%s\n' "$_p" ;;
+    *) printf '%s/%s\n' "$_base_dir" "$_p" ;;
+  esac
+}
+
+CURRENT_TEXT_PATH=$(resolve_path "$VALUE_TEXT_FILE" "$RUNTIME_DIR")
+CURRENT_JSON_PATH=$(resolve_path "$VALUE_JSON_FILE" "$RUNTIME_DIR")
+STATE_PATH=$(resolve_path "$STATE_FILE" "$RUNTIME_DIR")
+EXPORT_VARS_PATH=$(resolve_path "$EXPORT_VARS_FILE" "$RUNTIME_DIR")
 INDEX_PATH="$RUNTIME_DIR/index.html"
-RESULT_PATH="$CFST_WORK_DIR/$CFST_RESULT_FILE"
+RESULT_PATH=$(resolve_path "$CFST_RESULT_FILE" "$CFST_WORK_DIR")
 UPDATED_AT=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
 
 mkdir -p "$RUNTIME_DIR"