# vmess-domain-rotator This repo provides a first working version of an automated pipeline: 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. Edit `config.json` directly (single runtime config file). For your sample response (`data.good[].ip`), parser config can be: ```json "parser": { "field_paths": ["data.good[].ip"], "json_paths": [], "regex": "[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}" } ``` 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: ```json "healthcheck": { "enabled": false } ``` 2. Run once: ```bash python3 scripts/domain_updater.py --config config.json ``` 3. Check output files: - `runtime/current_domain.txt` - `runtime/current_domain.json` - `runtime/state.json` ## What the script exports - `current_domain.txt`: plain text domain. - `current_domain.json`: machine-readable payload: ```json { "domain": "best.example.com", "updated_at": "2026-04-13T07:00:00Z", "status": "ok", "source_count": 15, "checked_count": 10 } ``` - `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. ## How to connect with Sub-Store Two practical modes: 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. Minimal smoke test (local): ```bash python3 -m http.server 8080 --directory runtime ``` Then test: ```bash curl http://127.0.0.1:8080/current_domain.json ``` ## 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. Then reload service: ```bash systemctl reload v2ray ``` ## Update Base64 VMess links If your node list uses `vmess://`, use: ```bash python3 scripts/update_vmess_links.py \ --input ./nodes.txt \ --output ./nodes.updated.txt \ --domain-file ./runtime/current_domain.txt ``` Only update specific node names (`ps`) by regex: ```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)" ``` If the whole subscription file is itself base64-encoded, add: ```bash --subscription-base64 ``` ## Scheduling ### Cron ```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 ``` ### systemd timer Use files under `systemd/` and adjust paths/user. Default timer interval in this repo is `1h`. ### Debian install/uninstall scripts Install on a Debian server (creates systemd service+timer): ```bash sudo bash scripts/install_debian.sh ``` If you run this inside a git clone, installer now defaults to in-place mode (service uses current repo path), so auto-commit writes to your real repo. To force copy deployment under `/opt`, set `--app-dir` explicitly. This installer initializes a git repo under app dir only in copy mode (if missing). Runtime updates are committed and pushed to `runtime-state` branch by default when selected domain changes, so `main` stays clean. Uninstall: ```bash sudo bash scripts/uninstall_debian.sh ``` Useful options: ```bash sudo bash scripts/install_debian.sh --user root --group root --interval 5min sudo bash scripts/install_debian.sh --app-dir /opt/vmess-domain-rotator sudo bash scripts/uninstall_debian.sh --keep-app-dir ``` ## Config notes - 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. ## 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. Common deployment cases: - Docker: check mounted volume path, then back up that volume. - Node/PM2: check app directory `data/` or database file. In practice, you can avoid touching backend db files directly: 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 - Do not commit API tokens. - Use reverse proxy auth if exposing `current_domain.json` publicly. - Keep `runtime/state.json` persisted (for fallback).