GitHub-centered proxy availability pipeline with a home-router probe.
The goal is to separate two jobs:
- GitHub Actions stores and filters candidate nodes.
- Your iStoreOS/OpenWrt router tests candidates from a real mainland home network.
This avoids treating GitHub Actions or an overseas VPS as proof that a node works from mainland China.
.
├── .github/workflows/
│ ├── collect.yml # Pull candidate Clash YAML and export probe JSON
│ └── filter.yml # Filter final subscription from probe results
├── config/
│ └── probe.example.json # Router probe config template
├── data/
│ ├── candidates.yaml # Candidate Clash config
│ ├── candidates.json # Simplified JSON consumed by router probe
│ ├── final.yaml # Filtered Clash config for clients
│ └── alive/ # Probe result files
├── probe/
│ ├── probe.py # Run mihomo locally and test candidates
│ ├── push_github.py # Upload alive JSON to this GitHub repo
│ └── probe.sh # OpenWrt cron entrypoint
└── scripts/
├── export_candidates.py
└── filter_final.py
Create a repository:
hokiwork/china-proxy-probe
Add repository variable:
CANDIDATES_URL=https://example.com/candidates.yaml
CANDIDATES_URL should point to a Clash YAML containing a top-level proxies array. It can come from aggregator, Gist, or any other generator.
For multiple public sources, add repository variable SOURCES_JSON instead:
{
"sources": [
{
"type": "clash",
"url": "https://example.com/subscription.yaml"
},
{
"type": "text",
"url": "https://example.com/free-nodes.txt"
},
{
"type": "telegram",
"channel": "public_channel_name",
"follow_subscription_links": true
}
]
}Supported source types:
clash: Clash YAML with top-levelproxies.text: plain text, base64 subscription text, or a page containing proxy links.telegram: public Telegram channel page, usinghttps://t.me/s/<channel>. Whenfollow_subscription_linksis true, the collector also tries ordinary HTTP links in recent public messages and keeps only links that parse into proxies.
Do not commit private subscription URLs to a public repository. Put private or semi-private sources in GitHub repository variables or secrets.
This repository includes a public starter list at:
config/sources.public.json
The GitHub workflow uses this file by default. SOURCES_JSON still overrides it when you need private or custom sources.
Enable Actions. Run Collect candidates once. It will create:
data/candidates.yaml
data/candidates.json
Copy the probe/ directory and config/probe.example.json to your router, for example:
mkdir -p /mnt/sata/china-proxy-probeRecommended router path:
/mnt/sata/china-proxy-probe
Do not put large logs on /overlay.
Create config:
cp config/probe.example.json config/probe.json
vi config/probe.jsonSet:
github.owner:hokiworkgithub.repo:china-proxy-probegithub.token: fine-grained GitHub token with Contents read/write permission for this repoprobe.id: a stable name such ashome-telecommihomo.bin: path to your router's mihomo/clash binary
Run once:
sh /mnt/sata/china-proxy-probe/probe/probe.shIf it works, add cron:
crontab -e*/30 * * * * /bin/sh /mnt/sata/china-proxy-probe/probe/probe.sh >/tmp/china-proxy-probe.log 2>&1- The probe starts a separate local mihomo process. It does not modify your OpenClash/PassWall/Nikki runtime.
- Probe traffic must go directly through WAN. Do not route the probe process through an existing proxy chain.
- The mihomo controller started by the probe binds to
127.0.0.1only. - Keep the GitHub token on the router only. Never commit it.
Collect candidates workflow
-> data/candidates.yaml
-> data/candidates.json
Router probe
-> data/alive/<probe-id>.json
Filter workflow
-> data/final.yaml