Skip to main content
tunnelbyte ships three routing patterns. All use the same userspace WireGuard tunnel under the hood; they differ in how processes opt in.

Per-app - the default

$ tunnelbyte sin
 tunnel up via 5.223.57.171 (sin) - anonymous tier
  proxy: http://127.0.0.1:57412
The CLI brings up the WireGuard interface in-process and starts a localhost SOCKS5/HTTP proxy on an OS-allocated random port (printed as the proxy: line - don’t hardcode it). Your system default route is not modified. No sudo prompt. No wg-quick. Processes opt in by pointing at the proxy:
$ export HTTPS_PROXY=http://127.0.0.1:57412   # from the proxy: line above
$ curl https://api.ipify.org                  # uses the tunnel
Why this is the default: most dev tooling speaks HTTP proxy out of the box - Playwright, Puppeteer, curl, Python requests, Go’s http.Client, git, aws CLI, etc. - so opt-in is roughly zero cost. You can run multiple tunnels in parallel (one per region) without conflict, since each one binds its own port.

Wrapped child - tunnelbyte <region> -- <cmd>

$ tunnelbyte sin -- curl https://api.ipify.org
$ tunnelbyte fsn -- brave
$ tunnelbyte ash -- chrome https://api.ipify.org
Brings up a tunnel and launches the named command with the right proxy configuration injected for that program’s environment:
  • CLI commands (curl, git, wget, anything that respects HTTPS_PROXY env vars): the wrapper sets HTTPS_PROXY, HTTP_PROXY, and ALL_PROXY in the child’s environment. NO_PROXY is preserved + appended with localhost entries.
  • Known Chromium browsers (chrome, brave, edge, chromium, arc): the wrapper rewrites argv with --proxy-server=http://127.0.0.1:<port> and a dedicated --user-data-dir. Each browser gets its own persistent profile per (browser, region) under your config dir, so re-launching tunnelbyte fsn -- brave keeps logins, bookmarks, and extensions. Different regions get different profiles so cookies don’t leak across exit IPs.
  • Unknown GUI apps (Spotify, Slack, Discord, etc.): the wrapper falls back to the env-var path, which most GUI apps ignore. Use --all for these, or run them outside the wrapper and configure their proxy support manually.
The tunnel tears down when the wrapped command exits. The wrapped command’s own exit code is propagated.

System-wide - --all

$ tunnelbyte sin --all
[sudo] password:
 tunnel up via 5.223.57.171 (sin) - all traffic - anonymous tier
  (Ctrl-C to tear down and restore default route)
--all installs a 0.0.0.0/0 route via the tunnel interface, so every process on the machine sees the exit IP without any per-app configuration.
  • sudo is required each run. Nothing setuid is installed - the running tunnelbyte process itself flips routes (via netlink on Linux, route on macOS) while it holds elevated privileges, and restores them on exit. Caching the prompt across runs is a sudo setting, not ours.
  • On exit (Ctrl-C, expiration, crash), the original routing table is restored. If tunnelbyte is SIGKILL’d before cleanup runs, the next --all invocation detects and removes the stale route during pre-flight.
  • Only one --all tunnel can be active at a time (the OS only has one default route).
This is the closest thing to the consumer-VPN experience: open Slack, browse the web, run anything - it all egresses through the chosen region.

Which to use

Use caseMode
Scraper, CI job, Playwright, anything proxy-awareper-app
Multiple regions at once (CI runs against several)per-app
Open a fresh browser routed through the tunnel-- brave (or chrome/edge/chromium/arc)
One-shot CLI command routed through the tunnel-- curl ...
”Make my whole machine look like it’s in Singapore” demo--all
GUI apps that don’t speak HTTP proxy (Spotify, Slack)--all
All three modes use datacenter exit IPs. Targets that block by ASN (Cloudflare Bot Management, DataDome, etc.) refuse the connection regardless of routing mode or region - see the note in the introduction.

Behind the scenes

All three modes use userspace WireGuard by default rather than the kernel WireGuard module. The trade-offs:
  • No kernel modules, no wg-quick, no root for the WireGuard interface itself.
  • Throughput is bounded by the userspace TCP/IP stack. On modern hardware that’s still well into hundreds of Mbps - plenty for scraping, CI, and most dev workloads.
  • On Linux, --all automatically switches to the kernel WireGuard module when available, giving you the higher throughput without any extra flag. macOS always uses userspace.

See also

  • tunnelbyte - full CLI reference for the root command.
  • Tiers - what each tier gets you.