# warpscout picks the WARP edge node for you, and keeps its account file beside the binary

> warpscout is a Go scanner that walks Cloudflare WARP endpoint addresses, reports which edge node and exit region each one reaches, and emits an importable config. It is a single binary needing no admin rights and no TUN device, but its state model is a file on disk and its documented Go floor is a release behind what its module requires.

**vernette/warpscout** — 🛰️ Cloudflare WARP endpoint scanner - find working endpoints over wg/awg/masque and see the exit region and edge node they land on

- Repository: https://github.com/vernette/warpscout
- Stars: 473 · Forks: 47
- Language: Go
- License: MIT
- Published: 2026-09-17 · Updated: 2026-09-17 · Language: en
- Canonical page: https://hysenlabs.com/projects/vernette-warpscout

## The only thing it changes is which edge node you land on

Cloudflare WARP has thousands of endpoint addresses, and the address you connect to determines which edge node, called a colo, your tunnel terminates on. That is the entire problem warpscout addresses. Since April 2026, traffic through the Moscow node DME is described as filtered by DPI, and some sites simply do not open through it even though WARP itself reports a successful connection. The same configuration aimed at an endpoint on a different node does not have that problem.

The official client offers no way to choose a node, so warpscout walks the endpoint addresses itself, reports the node and exit region for each one, sorts the resulting table so the best entry is at the top, and can write a ready-to-import configuration for the winner.

The deployment constraints are unusually light for this category of tool. It is a single file with nothing to install, it needs no admin rights and no TUN device, and it runs on Windows, Linux, macOS, Android and Docker. That combination is what makes it usable on a router or in Termux, where a client that wants to install a system-level interface is not an option.

The account file is the price of that portability, and it is covered in its own section below because it is the one piece of state the tool cannot do without.

## Scanning will not start without a file next to the executable

The first step is a registration command, and its output is a file called `warpscout-account.json`, written next to the binary. The documentation is blunt about the consequence: you do it once, and without that file scanning will not start.

So the tool carries state, and the state lives wherever the executable happens to sit. On Windows that is wherever you unpacked the zip, for example a folder such as `C:\warpscout`. In a container it becomes the working directory, and the Dockerfile sets that deliberately:

```
FROM scratch

COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=build /warpscout /warpscout

WORKDIR /data

ENTRYPOINT ["/warpscout"]
```

Nothing in that file declares a volume, so the account file lands in the container's writable layer at `/data` and disappears when the container is recreated unless you mount something there. The final stage is `scratch`, which also means the image has no shell and no coreutils, so `docker exec` debugging inside the container is not available.

The build stage does the rest. It compiles a static binary with cgo disabled and path trimming, stamps the version into `main.version` with the leading v stripped from the argument, and compresses the result with UPX at its best LZMA level. The version argument defaults to `dev`, so a build with no argument produces a binary that reports itself as `dev`.

## Plain WireGuard is documented as getting through nowhere

Two protocol flags matter, and the documentation is opinionated about which to use first. AmneziaWG, selected with `-p awg`, is obfuscated WireGuard. Plain WireGuard is `-p wg`, and on filtering networks the project's own description is that it usually gets through nowhere at all, so the guidance is to start with `awg` straight away.

A second flag, `-P`, changes what the scan measures. On its own the scan records whether an endpoint connects; adding `-P` also measures latency and packet loss inside the tunnel. That takes longer and is recommended anyway, because without it the table is full of endpoints that complete a handshake and then pass nothing, which is precisely the failure mode the tool exists to detect.

A full scan takes a couple of minutes.

The dependency list explains the transport spread. AmneziaWG support comes from an amneziawg-go module pinned to a pseudo-version, which is an unreleased commit rather than a tagged release. QUIC and MASQUE support come from quic-go and from usque and connect-ip-go modules, both also pinned to pseudo-versions, so three of the project's core transports depend on commits that can change under a version number that looks fixed.

## Three conditions pick an endpoint, and four flags do it for you

Reading the table by hand means looking at the NODE column and choosing any row where the node is not DME, the loss figure is zero percent, and the ping sits on the lower side of the range. That is the entire selection rule.

The flags exist to remove the manual step. `-exclude-node DME` drops the Moscow node from consideration, and `-best` prints the single best address rather than a table, which in the documented example yields one endpoint on port 2408. The inverse form keeps only what you want, with `-country DE,NL` restricting to two countries and `-node HEL,ARN` restricting to two named nodes.

Configuration output is a separate flag rather than a mode. `-conf` writes a configuration file for the best endpoint straight away, and that file imports into the AmneziaWG client on Windows, Android, Linux and macOS like any other configuration. If the scan used plain WireGuard, the emitted file is a plain WireGuard configuration instead.

Beyond that, other client formats are covered including mihomo and usque, along with DNS, MTU and routing options, in a separate configuration document. The README in this copy is cut off inside the table-reading section, so the column definitions themselves are not visible here.

## Six install paths, each with its own obstacle

Windows takes a zip from the releases page, unpacked anywhere, then a Shift right-click into a PowerShell window in that folder, with an Unblock checkbox in the file properties if Windows complains about the downloaded file. The verification command is:

```powershell
.\warpscout.exe version
```

macOS has its own one-time gate. The first run is blocked because the file came from the internet, and the documented fix is to clear the quarantine attribute once with `xattr -d com.apple.quarantine warpscout`.

Linux, macOS, OpenWrt and Termux share a one-line installer piped into a shell, with a wget variant for systems without curl. The script picks the matching archive and installs into `~/.local/bin`, or `/usr/bin` on OpenWrt, or `$PREFIX/bin` in Termux, and running it again updates the install. Options go after `sh -s --`, and an `INSTALL_DIR` variable overrides the destination.

Arch Linux has two packages, one building from source and one taking the prebuilt release binary. Both are community-packaged, and the documentation is explicit that they are not maintained by this repository.

Android is the odd one out. There is no first-party APK; the recommended route is a separate application maintained by someone else, and the build itself only ships `android_arm64.tar.gz`, with the one-line installer working in Termux instead.

## The documented Go floor is one release behind what go.mod asks for

The source install instruction reads:

```sh
go install github.com/vernette/warpscout@latest
```

and is introduced as requiring Go 1.25 or newer. The module file declares `go 1.26.3`, and the container build uses a Go 1.26 Alpine base image. A user on Go 1.25 who follows the documented instruction will not get a build, because the module states a higher floor than the documentation advertises.

The same section has a second drift. The installer example pins a specific version:

```sh
curl -fsSL https://raw.githubusercontent.com/vernette/warpscout/master/install.sh | sh -s -- --version v0.8.1
```

against a current release of v0.16.0. As an illustration of the flag that is harmless, as an instruction it installs an eight-minor-old version with no note saying so.

The archive table is more precise and is worth reading before installing by hand. Windows is amd64 only, macOS has separate Apple silicon and Intel builds, Linux has amd64 and arm64, and Android is arm64 only. There is no Windows on arm and no Android on x86_64, which matters on Windows machines with arm processors where emulation is required, and on Android emulators.

OpenWrt shares the Linux archives, x86_64 routers taking the amd64 build and arm64 routers the arm64 one.

## One flat package with platform files picked by build tag

The source tree is roughly thirty Go files sitting at the repository root in a single package, with no internal directory. Platform-specific behaviour is separated by build tag through paired filenames: an Android and a generic variant of the argument handling, a Linux and a generic variant of the binding layer, a Windows and a generic variant of the console layer, and an Android-only DNS file.

The filenames also map the feature set onto modules. Endpoint walking and selection sit in the discovery and pool files, SNI probing and junk-endpoint filtering in their own files, QUIC and MASQUE transports in theirs, WireGuard configuration writing in another, SOCKS in another, and the tunnel and nested-proxy logic in two more. A report writer covers the on-disk output and a terminal UI layer covers the live table, backed by a bubbletea and lipgloss stack with bubbles components and terminal environment detection.

Testing is thin relative to that surface area. Three test files exist, covering the i1gen helper, the terminal UI and the WARP core, alongside two GitHub workflows referenced from the badges for releases and tests.

The Russian translation of the documentation lives alongside the English README, and the Docker path has its own guide under the English docs directory, so the four supported platforms are documented unevenly rather than not at all.

## Conclusion

warpscout is a focused tool for one specific problem, choosing a WARP endpoint whose edge node is not the one being filtered, and it solves it with a single file and no privileged access. Before running it, understand that the account file written next to the binary is required state and needs a persistent home in a container, and that the source-install instructions understate the Go version you will actually need.

## FAQ

### What does warpscout do?

It walks Cloudflare WARP endpoint addresses, reports the edge node and exit region each one reaches, sorts the results so the best is first, and can write a ready-to-import configuration for the best endpoint. It is a single Go binary needing no admin rights and no TUN device.

### How do I set up warpscout before scanning?

Run the register command, which writes warpscout-account.json next to the binary. The documentation states scanning will not start without that file, and the Docker image sets its working directory to /data for that state, so a container needs a volume mounted there.

### Which protocol should I scan with in warpscout?

Start with -p awg, which is AmneziaWG obfuscated WireGuard, because on filtering networks the project reports that plain WireGuard with -p wg usually gets through nowhere at all. Adding -P measures latency and packet loss inside the tunnel, which takes longer but weeds out endpoints that connect and pass nothing.

### How do I get a config file from warpscout?

Add -conf and a filename to the scan, which writes a configuration for the best endpoint. It imports into the AmneziaWG client on Windows, Android, Linux and macOS, and scanning with -p wg produces a plain WireGuard configuration instead. Other formats including mihomo and usque are documented separately.

### Does warpscout change what Cloudflare WARP collects about me?

No, and the repository does not address WARP's privacy properties at all. It only selects which endpoint address your existing WARP configuration connects to, which changes the edge node and exit region you land on and nothing about what the tunnel provider observes.

### Can I install warpscout on OpenWrt or in Termux?

Yes, the one-line install script covers Linux, macOS, OpenWrt and Termux, choosing the matching archive and installing into ~/.local/bin, or /usr/bin on OpenWrt, or $PREFIX/bin in Termux. Running it again updates the install, and x86_64 routers take the amd64 Linux archive while arm64 routers take the arm64 one.

## Sources

- [Issues](https://github.com/vernette/warpscout/issues)
- [License: MIT](https://github.com/vernette/warpscout/blob/master/LICENSE)
- [README](https://github.com/vernette/warpscout/blob/master/README.md)
- [Releases](https://github.com/vernette/warpscout/releases)
- [vernette/warpscout on GitHub](https://github.com/vernette/warpscout)

---

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