cfnb: a Cloudflare IP optimizer that measures before it writes DNS
这是一个全自动的 Cloudflare CDN 节点优选工具。它通过 TCP 延迟筛选 + IP 可用性二次检测 + HTTP 延迟及抖动检测 + 真实带宽测速 多重机制,从多个公开数据源中聚合节点,自动识别并解析任意格式(标准代码、中文名、emoji国旗、JSON等),筛选出当前网络环境下速度最快、延迟最低、抖动最小的 Cloudflare IP,并支持自动更新至 Cloudflare DNS 以及同步至 GitHub 仓库,同时支持微信实时通知。
At a glance
- What is it?
- cfnb does not pick a Cloudflare address from a list and hope. It runs four stages of measurement, aggregates candidates from several public data sources in whatever format they are published, weights the results, and only then rewrites the DNS records for your domain. The token handling is the part to read twice.
- Who is it for?
- Adopt cfnb if you serve a domain through Cloudflare from a network where the addresses Cloudflare hands out are slow or uneven, and you want the choice of IP made from measurements taken on your own link rather than from a list someone else published. Do not adopt it to solve a problem it cannot see, because it changes which addresses your domain resolves to and nothing else.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 3 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Four measurement stages, and a weighted decision at the end
The tool is described as a fully automatic Cloudflare CDN node selection utility, and the measurement pipeline is the substance of it.
The first stage is a TCP connection test, which measures latency concurrently and applies a success rate threshold, so an address that answers sometimes is discarded rather than kept with a bad average. The second is an availability re-check that uses an API to verify proxy capability, which catches candidates that complete a TCP handshake but are not usable as an edge. The third measures HTTP latency and jitter, by probing the response several times and computing the average latency and the standard deviation, and it filters out addresses that are not Cloudflare nodes at all, which is also a proxy compatibility filter. The fourth is a real bandwidth test, using curl to download and measure throughput rather than inferring it from latency.
The final step is a composite weighted ranking. Bandwidth, TCP latency, HTTP latency and jitter are all taken into account, and the four weights can be adjusted freely, so the tool can be pointed at a link where bandwidth matters more than latency, or the other way round. The output is the Cloudflare IP that is fastest, has the lowest latency and the lowest jitter on the network the tool is running on.
Two modes are supported for the selection, a global best N and a best N per country, and there is a set of pre-filters that run in order before the TCP test, namely a port filter, a blacklist filter and a whitelist filter, each of which can be switched on or off.
The point of the staging is that each stage is cheaper than the next. A TCP test across thousands of candidates is fast, a bandwidth test is not, so the tool narrows the field first and measures thoroughly at the end.
Some filters change the DNS, others change nothing at all
The feature table distinguishes carefully between filters that affect the measurements and filters that only affect what gets written, and that distinction is the one to understand before running the tool.
Three filters are explicitly scoped to the DNS update step only. The DNS blacklist removes nodes in specified countries when the records are updated. The IPv6 landing filter drops nodes whose landing is IPv6 only and keeps IPv4 and dual stack ones. And the IP risk level filter allows only low risk nodes, with a fallback to a different behaviour when a high risk address is found. The README marks all three with the same parenthetical note, and the reason is consistent: they change which address your domain points to, not which addresses were measured.
That distinction matters for how you read a result. If the tool tested an address in a country you have blacklisted, and then excluded it when writing DNS, the report and the deployment differ, and the report is not wrong.
There is also a forced direct connection mode. It is a switch that clears the system proxy, so that all test traffic goes out directly rather than through a proxy. That is an important detail for a tool whose purpose is to find the best path to Cloudflare, because a proxy in the path would measure the proxy rather than the link.
The region calibration works the other way round. Node country codes are queried asynchronously and concurrently through ipinfo.io, and the results are cached for reuse, and a list of ipinfo.io API tokens, one per line, lives in valid_tokens.txt in the repository root. The country code is what the per-country selection mode and the country blacklist both rely on, so this step is not decoration, it is the input the filtering needs.
Aggregation means parsing whatever the data source happens to publish
Candidate addresses come from multiple public data sources, and the tool has to cope with the fact that they do not agree on how to name a country.
The aggregation is adaptive and the README says it automatically recognises and parses any format, giving the examples as standard codes, Chinese names, emoji flags and JSON, and converting everything to a standard format. That is a small problem on paper and an annoying one in practice, because a list that names one country as a two-letter code and the next as a flag emoji has to be normalised before anything else can be filtered on it.
The same commitment to not caring about the source's conventions runs through the rest of the design. There is no quality threshold on the data, only a parsing layer, and the per-country and global selection modes are computed after normalisation, so a source that only lists a subset of the address space does not silently narrow the result set.
The tool also keeps a copy of the result, in a file called ip.txt, which is overwritten on every run and pushed to a GitHub repository, so that other machines or other people can subscribe to the same list without running the measurement themselves. The push is done by a separate script per platform, a PowerShell script on Windows and a Bash script on Linux, and both force the push of ip.txt.
For a reader, the important consequence is that the measurement is local while the list is shared. The addresses are chosen on your network, and the result is published so that somebody else can start from it.
Deployment is a script and a scheduler, on two platforms
The installation is a one-line dependency install plus a setup script, and the README gives the full procedure for both operating systems.
The system requirements are Windows 10 or Windows Server 2016 and later, or Linux on distributions such as Ubuntu, Debian and CentOS, plus Python 3.7 or newer, Git, and curl available on the path. The Python dependencies are requests, aiohttp and brotlicffi, and the manual install is:
pip3 install requests aiohttp brotlicffiOn Linux the system packages come from the distribution's package manager:
sudo apt update
sudo apt install -y python3 python3-pip git curlThen the setup script does the work, and the README is explicit that it installs the dependencies, creates the .gitignore and configures the scheduled run, which is every five minutes on the hour. On Linux that means a cron entry, and the manual version of it is in the README:
(crontab -l 2>/dev/null; echo "*/5 * * * * cd $(pwd) && nice -n -10 /usr/bin/python3 $(pwd)/main.py >> $(pwd)/cron.log 2>&1") | crontab -On Windows the same interval is a scheduled task, configured through the Task Scheduler with a repeat interval of five minutes, an indefinite duration, and the priority set to high, and running with the highest privileges whether or not the user is logged on.
The scripts are named by purpose. main.py is the core program, doing the fetching, testing, filtering, updating and pushing. config.json holds all the runtime parameters with detailed comments. setup.ps1 and setup.sh install the dependencies and configure the scheduler. git_sync.ps1 and git_sync.sh push ip.txt. And update_fork.ps1 and update_fork.sh exist for a specific problem, the case where a fork or a changed remote makes git pull fail with refusing to merge unrelated histories, or makes every push ask for a browser login. The presence of a dedicated repair script for that failure mode is a good sign about how the project is used.
Three tokens, and the switches that turn each feature off
The token section is the part of the documentation that deserves the most attention, because it is where the tool's reach is decided.
Three credentials are optional, each tied to a feature. The GitHub personal access token, used by the push scripts, is a classic token, and the instructions say the expiration must be set to no expiration and that the only scope to select is repo. The Cloudflare API token is created from the edit zone DNS template, with the zone resource set to your domain, and the permissions are pre-filled as zone, DNS, edit. The WxPusher credentials are an app token and a list of user identifiers, for the WeChat notifications, and the app token is shown only once when it is created.
Each feature can be switched off in config.json, and the README is explicit about the values. Setting ENABLE_WXPUSHER to false disables the notifications. Setting GITHUB_SYNC_MAX_RETRIES to zero turns off the GitHub push. And setting CF_ENABLED to false turns off the DNS update, which is the feature with the widest blast radius, since it replaces the address records for your domain.
The privacy note in the feature list says the .gitignore ignores sensitive files, and the file manifest confirms the shape of the repository: main.py, config.json, the four platform scripts, the update_fork pair, ip.txt for the current result, and valid_tokens.txt for the ipinfo.io tokens. So the credentials live in plain text files in the working directory, which is exactly why the .gitignore entry matters and exactly why a fork needs the repair scripts, since a bad push would publish them.
For a tool that runs unattended every five minutes, that arrangement is reasonable, and the review of what you paste where is a one-time cost.
What the tool does not do, and what it changes
It is worth being precise about the scope, because the name suggests more than the tool does.
The tool does not change how your site is served, it does not change your content, and it does not give you a faster origin. It chooses which Cloudflare addresses your domain resolves to, and it measures that choice on the network the tool runs on. Everything else about the request path stays the same, and if the bottleneck is your origin or the path to the origin, no IP selection will fix it.
The measurement is also local by definition. The result is the best of the candidates on one network at one moment, and the tool runs every five minutes, so the answer is refreshed constantly and can differ between two networks in the same building. The published ip.txt is therefore best understood as a starting point for a subscriber rather than as a definitive list.
The DNS update itself is described as an atomic batch replacement of the same-named A and TXT records. Atomic matters because a partial write would leave a domain resolving inconsistently, and because the records being replaced are the ones that point at Cloudflare.
There is one operational risk that is not a limitation of the software but of the deployment. The instructions ask for a GitHub token with no expiration and the repo scope, which is a credential that can push to repositories, held on a machine that runs unattended. The .gitignore and the fork repair scripts are the mitigations the project offers, and the alternative is to run the tool with the GitHub push disabled and consume the results some other way.
Editorial conclusion
Adopt cfnb if you serve a domain through Cloudflare from a network where the addresses Cloudflare hands out are slow or uneven, and you want the choice of IP made from measurements taken on your own link rather than from a list someone else published. Do not adopt it to solve a problem it cannot see, because it changes which addresses your domain resolves to and nothing else. Before you run it, set the tokens you do not need to disabled in config.json, note that the GitHub token instructions ask for a classic token with no expiration and the repo scope, and check the scope of the Cloudflare token, which the README says should be limited to editing DNS for your zone.
Frequently asked questions
What does the cfnb tool do?
It is a fully automatic Cloudflare CDN node selection tool that aggregates candidate addresses from several public data sources, measures them with a TCP latency test, an availability re-check, HTTP latency and jitter detection and a real bandwidth test, then picks the fastest, lowest latency and lowest jitter address for your network.
How does cfnb update my DNS records?
It performs an atomic batch replacement of the same-named A and TXT records, which is why the Cloudflare API token instructions specify the edit zone DNS template scoped to your domain. The DNS update can be switched off entirely by setting CF_ENABLED to false in config.json.
What are the system requirements for cfnb?
Windows 10 or Windows Server 2016 and later, or Linux, plus Python 3.7 or newer, Git and curl on the path. The Python dependencies are requests, aiohttp and brotlicffi, and the scheduled run is configured every five minutes through Task Scheduler on Windows or cron on Linux.
Which tokens does cfnb need and can I turn features off?
A GitHub personal access token for pushing the result file, a Cloudflare API token with DNS edit rights for your zone, and WxPusher credentials for the WeChat notifications, each of which is optional. Setting ENABLE_WXPUSHER to false disables the notifications and setting GITHUB_SYNC_MAX_RETRIES to zero disables the GitHub push.
How does cfnb pick and name candidate addresses?
The aggregation is multi-source and adaptive, and the tool automatically recognises and parses any format the sources use, including standard codes, Chinese names, emoji flags and JSON, converting them to a standard format. Node country codes are then calibrated through ipinfo.io with concurrent lookups and cached results.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/xinyitang3-cfnb)Was this useful?