# proxy-checker measures a proxy from the server that will actually use it

> proxy-checker is a self-hosted Python service that pulls public free proxy lists, tests each one from the machine you deploy it on, and keeps the survivors in a repository you can subscribe to as TXT or JSON. Its most interesting property is a refusal: v6.0 deleted the account-registration check on purpose, and the Cloudflare label was renamed so the tool stops promising what it cannot deliver.

**strongshuai/proxy-checker** — Proxy Checker is a self-hosting-first, free tool for checking, filtering and maintaining proxies: it pulls continuously updated public proxy sources, batch-tests HTTP, HTTPS, SOCKS4, SOCKS5 and SOCKS5H, keeps the working ones in "My Repository", and generates stable TXT/JSON links that scripts, services or other tools can pull directly. Useful if you regularly work with proxies, account farms or API connectivity.

- Repository: https://github.com/strongshuai/proxy-checker
- Website: https://linux.do/t/topic/2390702
- Stars: 450 · Forks: 102
- Language: Python
- License: MIT
- Published: 2026-09-17 · Updated: 2026-09-17 · Language: en
- Canonical page: https://hysenlabs.com/projects/strongshuai-proxy-checker

## Reachability is a property of the host you run the check from

The whole design argument fits in one diagram the project puts near the top:

```text
你的检测服务器 -> 代理 IP -> 目标服务
```

Three hops, and the first one is you. A proxy that answered on somebody else's machine proved that their route to the proxy and on to the target works. It says nothing about whether your machine can open a socket to that same proxy IP, through your own ISP, from your own country, behind your own firewall. The project is blunt about this and positions itself as the opposite of a leaderboard, describing itself as not the kind of list where someone tested it elsewhere and assumes it works for you.

So the deployment advice is not incidental. Running this on the host that will actually make the requests is what makes the result mean anything, and that is also why the tool reports the exit IP, the country and the IP type for every survivor instead of a bare HTTP status. A status code tells you a page came back. The exit IP tells you who came back as.

The pool it draws from is large and disposable. Public sources such as Proxifly, TheSpeedX, ProxyScrape and GeoNode are aggregated with several more, deduplicated by proxy address, and the README puts the aggregate at 10,000 or more entries at typical times while stating that final quality comes from your own results. Aggregation is a convenience. The grading is the product.

## Five check modes, where a 401 is treated as a success

Five modes ship: `generic` for ordinary proxy checking, then one each for `openai`, `grok`, `gemini` and `claude`. The specialised ones probe named targets, so `openai` looks at the ChatGPT home page, the OpenAI API domain and Cloudflare status, while `grok` covers grok.com and the xAI API, `gemini` covers gemini.google.com and the Gemini API, and `claude` covers claude.ai and the Anthropic API.

The interesting decision is how results are read. An API returning `401` or `403` counts as the API domain being reachable, because the response proves the network path arrived at the server. The tool states plainly that this does not mean the account, the key or the quota is usable, which is the correct reading and the opposite of what a status-code column usually implies. Cloudflare status is deliberately kept separate: it affects only the judgement about web pages and is never used to downgrade API reachability.

Results carry a grade of A, B, C, D or F with a recommended use attached, such as basic proxy, web usable, API usable, web plus API, unstable, or dead. Protocols covered are HTTP, HTTPS, SOCKS4, SOCKS5 and SOCKS5H, and an address typed without a protocol prefix is identified automatically. A failed home page no longer ends the check, because the run continues to the API and the exit IP so an API-only proxy is not thrown away.

## v6.0 deleted the registration check and relabelled the Cloudflare result

Earlier versions tested whether a registration page or account entry point could be opened. v6.0 removed that, and the reasoning is the most transferable thing in the repository: being able to open a registration page does not mean registration succeeds, because success also depends on risk control, phone number, email, browser environment, past behaviour and regional policy. Concluding from an HTTP status is misleading, so the check is gone. What remains is the narrower claim that the proxy works from your server and the target page or API is reachable.

The same honesty pass renamed a label. What the interface called Cloudflare bypass became a statement that the page was not intercepted this time, with a hover note spelling out that this does not guarantee registration, login, Auth0 or any other account flow will pass. The wording on the failure side became page intercepted by Cloudflare. Renaming a button is cheap. Doing it because the old name made a promise the code could not keep is a design decision, and it is the clearest signal of how the maintainers think about their own tool.

This is also where the wrong-tool boundary sits. If what you need to know is whether an account can be created through a given proxy, this project will not tell you, on purpose. If what you need is a list of proxies that answered from your host, it is the right shape of tool.

## The repository is public by URL and scoped to a browser token

The share links stay public, by design, so other programs can fetch them directly. TXT suits a proxy subscription, JSON keeps the grade, country, recommended use and service reachability. Each browser generates its own stable token, so a public deployment does not have users overwriting each other. Two things follow that are worth sitting with. First, your working proxy list is readable by anyone holding the URL, so treat that link as a secret even though it is a convenience feature. Second, the repository belongs to a browser profile rather than to an account, so a wiped profile means a new token and a new repository.

v6.3 fixed a data-bleed bug in exactly this area. Cloud repository reads used to fall back to a shared public `default` repository, which meant historical records could cross between different users' tokens. Reads no longer fall back. The same release fixed a case where restoring from an already-emptied cloud kept stale local proxies and looked like data had come back from nowhere; restoring from an empty cloud now clears the local repository explicitly and records that the user cleared it, so a page refresh does not resurrect the old cache.

The paid-provider route is the real alternative here, and the difference is in what you are buying. A paid pool is curated by somebody else and you pay for its availability. This one aggregates public free sources, grades them from your host, and hands you a list you can filter and re-test yourself. Free is why the pool churns, which is why grades, stability flags, and policies named `stable_only`, `include_unstable` and `archive_all` exist at all.

## Default password linux.do, port 8888, and one declared dependency

The service ships with the default password `linux.do` and says to change it once the instance is live. The login handling is better than a hidden overlay: on a same-origin self-hosted deployment, an unauthenticated request returns a standalone login page and the main interface HTML and `app.js` are not served at all. State uses an HttpOnly cookie, and a cross-origin static frontend can instead use an access token returned after login.

Port 8888 is the published default, and the changelog repeats across releases that the default stays public while a private deployment port is deliberately not written into the public project. That is a reasonable habit and also a fixed, guessable target, so treat the password as the only thing standing between the internet and a service that will make thousands of outbound requests on your behalf.

Serverless is ruled out by the tool itself: Vercel and similar platforms do not support resident background tasks, and the interface says so plainly rather than failing later. That makes the self-hosted Python service the only supported shape.

Installation is where the documentation is thinnest. requirements.txt declares exactly one runtime requirement:

```text
curl_cffi>=0.14.0
```

Everything else sits in plain files at the root: `server.py`, `proxy_check.py`, `fetch_proxies.py`, `config.json`, `index.html`, `app.js`, `login.html`, plus `api/` and `tools/`. The visible README contains no install command and no start command. The only pointer to obtaining it is the project link and a linux.do thread in the homepage field, so getting it running means reading the thread or the code.

## v6.3 swapped a firehose of async tasks for a worker queue

The scaling story is told as bug fixes, which makes it easy to read. v6.3 stopped creating every asynchronous task at once and moved to a fixed-size worker queue, aimed at the case of tens of thousands of proxies where task pileup and memory pressure were the problem. Each proxy also got an independent hard timeout, so a request that never returns as expected is recorded as an F-grade failure and the run continues instead of stalling the round. Stopping an automatic task now cancels unfinished workers, so the state does not sit at `stopping` for long, and the summary gained `last_progress_at` so you can see when the task last produced a result.

v6.1 fixed the browser side. The first render covers 400 rows with a show more control, results are written to localStorage on a delay instead of serialising a large JSON on every poll, and filtering re-renders from the data rather than hiding items one at a time inside a huge DOM. History restored after a refresh goes through the same batched path.

The check itself is deliberately bounded. Rounds default to 2 and the cap stays at 3, with the stated reason being that batch checking free proxies should not be dragged out. Concurrency is configurable, and the changelog notes a fix to confirm it genuinely took effect, since the frontend submits `max_concurrent` and the backend applies the limited value to both an `asyncio.Semaphore` and the HTTP client connection count. Settings also cover request timeout, protocol detection timeout, login validity, log retention and default timezone.

## Automatic tasks run server-side and lock out manual checks

Scheduled runs are a backend feature of the self-hosted service, not a browser timer, and they continue after the browser is closed. Two schedules are offered: every N hours, or a fixed time of day in a chosen timezone. A run pulls all the free sources, merges in the proxies from your repository, deduplicates by proxy string, then checks the batch under the configured rounds, concurrency and mode. You can restrict it to new proxies only or force a full pass.

Two safety behaviours matter. An automatic task in progress intercepts manual checks, so one server is not hammered by two jobs at once. And re-test cleanup is on by default: an older repository proxy that takes part in a round and is judged dead gets removed, while an exception that aborts the whole task does not delete your existing repository. That distinction between per-item failure and task-level failure is the difference between a self-maintaining list and an empty one.

Six endpoints back this: `/api/auto/get`, `/api/auto/save`, `/api/auto/run-now`, `/api/auto/stop` and `/api/auto/status` are named in the changelog, and progress is shown in the status area. Manual runs survive a page refresh: the UI state is restored and it resumes polling the same backend task, and detection logs for both manual and automatic runs record start and end times, mode, rounds, concurrency, counts and a valid or dead summary.

One upgrade hazard is worth naming. Writes to the cloud repository were made safe-merge by default after automatic tasks were found overwriting old local records, and overwrites now carry a `base_count` check that refuses the write when the cloud has already moved and tells you to refresh first.

## The README is Chinese, changelog-shaped, and stops mid-sentence

Worth knowing before you plan an adoption: the project description and README are written in Chinese, and their composition is unusual. After a short section on who the tool is for and eight capability sections, the document turns into release notes covering v6.2 to v6.3, v6.1 to v6.2, v6.0 to v6.1 and v5.0 to v6.0. The final line breaks off partway through a sentence about merging the frontend entry points and `index.html` and `app.js` at the root, so the oldest notes are incomplete in what was published.

The imbalance is the practical problem. You get a precise account of what changed and almost no account of how to configure anything. There is no configuration reference, no API reference beyond the five automatic-task endpoints named in passing, and no start command. Many changelog entries are also about presentation rather than behaviour: button labels gaining emoji, a grid becoming equal width, animation timings shortening with support for `prefers-reduced-motion`, a status line moving to a different part of the header. Those are real changes and they are easy to read, but they do not help you decide whether the thing fits.

A `PRODUCT.md` sits at the root next to the README, which is where to look first. If you need to know what a setting does before changing it, this repository will not tell you, and you should expect to read `config.json` and the Python files.

## Conclusion

Adopt proxy-checker if you consume free proxies from a specific host and care about the path from that host rather than a global verdict, and if you are willing to run a password-protected service on port 8888 whose working proxy list is readable by anyone holding the URL. Do not adopt it to find out whether you can register an account, because v6.0 removed that check on purpose, and do not adopt it if you need a stable feed, since the pool is public free sources that churn, which is why the grade, stability and archive_all policy exist. Verify three things first: change the default password linux.do before the service is reachable, decide whether public TXT and JSON share links are acceptable for your working list, and read the v6.3 note about cloud reads no longer falling back to a shared default repository, since that fix is what stops one user's token showing another's history.

## FAQ

### Does proxy-checker tell me whether I can register an account through a proxy?

No. v6.0 removed registration page and account entry checks, because opening a registration page does not mean registration succeeds, which also depends on risk control, phone number, email, browser environment, past behaviour and regional policy. It now reports only whether the proxy works from your server and whether the target page or API is reachable.

### What does a 401 or 403 response mean in proxy-checker results?

It counts as the API domain being reachable, because the response shows the network path reached the server. It explicitly does not mean the account, key or quota is usable, and Cloudflare status is kept separate so it affects only the judgement about web pages.

### What is the default login password for proxy-checker?

The default password is linux.do, and the project advises changing it immediately after the instance goes live. Login state uses an HttpOnly cookie, and a cross-origin static frontend can use an access token returned after login instead.

### Are my proxy-checker repository TXT and JSON links private?

No. The share links stay public so other programs can fetch them directly, with TXT suited to proxy subscriptions and JSON keeping grade, country, recommended use and service reachability. Each browser generates a stable token so public deployments do not overwrite one another.

### Which proxy protocols can proxy-checker test?

HTTP, HTTPS, SOCKS4, SOCKS5 and SOCKS5H. An address written without a protocol prefix is identified automatically, and results are graded A, B, C, D or F with a recommended use such as basic proxy, web usable, API usable, web plus API, unstable or dead.

### Can proxy-checker run scheduled background tasks on Vercel?

No. Serverless platforms do not support resident background tasks and the interface says so explicitly. The self-hosted Python service keeps scheduled runs going after the browser is closed, on an every N hours schedule or a fixed daily time in a chosen timezone.

## Sources

- [License: MIT](https://github.com/strongshuai/proxy-checker/blob/main/LICENSE)
- [Project website](https://linux.do/t/topic/2390702)
- [README](https://github.com/strongshuai/proxy-checker/blob/main/README.md)
- [Releases](https://github.com/strongshuai/proxy-checker/releases)
- [strongshuai/proxy-checker on GitHub](https://github.com/strongshuai/proxy-checker)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/strongshuai-proxy-checker
