Making wanctl fast: proxies, large files, and checking the path

Every wanctl command goes through the relay, and it makes several round trips there: it opens a connection, runs an end-to-end TLS handshake with the device, and only then runs the command. Any delay added on the way from your machine to the relay is paid several times per command, so that stretch of network is what decides how smooth wanctl feels.

Behind a proxy, send the relay direct

With a proxy client in TUN mode, traffic to the relay is routed by the proxy's rules, and it easily lands on a node far away. One measurement (2026-09-25, Beijing): a Mac running Clash Verge in TUN mode had its traffic to a Hong Kong server routed through a Los Angeles node, with a median time to first byte of 1.25 s and a worst case of 3.9 s; at the same moment a direct connection from home took 0.11 s.

First find out which relay you use. It is the relay line of the output (it is also in wanctl status):

wanctl config

Then add a DIRECT rule for that domain, at the very top of your rules so that no earlier rule from your subscription catches it first. In a mihomo / Clash config file it looks like this:

rules:
  - DOMAIN,wanctl-relay.z10.dev,DIRECT
  # ...your existing rules

In Clash Verge Rev, do not edit the subscription file itself: the next subscription update overwrites it whole. Open the subscription's menu, choose "Edit Rules", and add the line with "Prepend Rule". Afterwards find the relay's domain on the Connections page and check that it goes DIRECT. Other proxy clients work the same way.

wanctl only uses proxies from environment variables

wanctl does not read system proxy settings: the proxy in macOS network settings, Windows Internet Options, and a proxy client's "system proxy" switch have no effect on it. It reads only the HTTPS_PROXY, HTTP_PROXY and NO_PROXY environment variables (either case). That leaves three situations:

  • The proxy client only has "system proxy" on, TUN is off, and no proxy variable is set in your terminal: wanctl already connects directly, nothing to do.
  • TUN is on: add the DIRECT rule from the previous section.
  • HTTPS_PROXY is set in your terminal: wanctl goes through that proxy, and it does not use HTTP/3.

In the third case, add the relay to NO_PROXY so wanctl connects directly. Where UDP gets through, wanctl switches to HTTP/3 by itself, which is much faster on networks that throttle TCP; through a proxy it cannot:

export NO_PROXY="$NO_PROXY,wanctl-relay.z10.dev"

Note that an agent installed as a service with wanctl service install does not see variables you set in your terminal or shell profile, while an agent launched from a terminal with wanctl start inherits that terminal's variables.

The other way round: if your network lets UDP through but carries it worse than TCP (some TUN-mode proxies do), set WANCTL_HTTP3=0 to keep wanctl on HTTP/2. See the environment reference.

Large files: push up to 1 GiB, use another tool beyond that

wanctl push takes at most 1 GiB per file. A larger file is refused before anything is sent:

wanctl: upload size 1073741825 outside supported range 0..1073741824

pull has no such limit, but both go all the way through the relay, so their speed depends on each end's network to the relay, and an interrupted transfer starts over from the beginning. So:

  • A directory or a pile of small files: pack it into one archive first. push and pull move one file at a time, and every file opens a new connection to the device.
  • Anything over 1 GiB, or anything large you move repeatedly: if the two machines can reach each other over SSH, use scp or rsync (rsync can resume); if they cannot, go through cloud storage or an object store.

When it feels slow, check yourself

Go through these in order; each step rules out one cause.

Versions first. Run wanctl version here and wanctl status --target DEVICE for the other end, which reports that device's agent version. HTTP/3 arrived in v0.13.0. Agents update themselves by default; on the controller, run wanctl update.

Then measure the path itself. Once the first two sections have you going direct, run this a few times. It prints the time to first byte from the relay, in seconds:

curl --noproxy '*' -so /dev/null -w '%{time_starttransfer}\n' https://wanctl-relay.z10.dev/healthz

For reference, the direct connection in the measurement above took 0.11 s. If you are already direct and this number is still large, the path from your network to the relay is slow in itself. There is nothing to tune on the wanctl side; move large files with another tool as described above.

Last, see whether HTTP/3 is helping. wanctl does not show which protocol it is using, but you can compare on the controller: push the same file of a few tens of MB several times normally and several times with HTTP/3 off. Network speed wobbles, so a single run of each proves nothing.

time wanctl push --target DEVICE ./test.bin /tmp/test.bin
time WANCTL_HTTP3=0 wanctl push --target DEVICE ./test.bin /tmp/test.bin

If it is clearly faster with HTTP/3 off, your network lets UDP through but carries it badly, so keep WANCTL_HTTP3=0 from now on. If the two are about the same, HTTP/3 is not in use (for example because UDP is blocked and wanctl has already fallen back to HTTP/2), or the bottleneck is elsewhere.