Skip to content

Proxies, VPN tunnels, and circumvention — pick the right tool

Three different tools for three different problems

Section titled “Three different tools for three different problems”

“Proxy” is a word that gets used for at least three families of tools with different goals, threat models, and trust postures. Picking the right one depends entirely on what you’re actually trying to do.

The Wikipedia article on internet censorship circumvention puts the distinction well:

Systems for circumvention and anonymity are different. Circumvention systems bypass blocking but do not protect identities. Anonymous systems protect identities but aren’t primarily designed for circumvention.

A few acronyms used below: GFW = Great Firewall (of China); DPI = Deep Packet Inspection (the technique a censor uses to inspect and classify traffic); SNI = Server Name Indication (the unencrypted hostname field in a TLS handshake that censors most commonly fingerprint); REALITY = the active-probe-resistance layer used with VLESS, which makes a TLS handshake to your server look like a real handshake to a third-party CDN site.

CategoryGoalThreat modelExamplesWhere to go
1. Anonymity networksHide who you are from the destination and from observersPassive ISP / global passive adversary; logging by destinationTor, I2PCategory 1 below
2. VPN-style tunnelsCarry your traffic through a trusted relay you control or payLocal network observer; geo-blocks; ISP loggingWireGuard, OpenVPN, Mullvad / IVPNCategory 2 below
3. Censorship-circumvention / obfuscated proxiesSurvive an active state-level censor that’s trying to fingerprint and block your tunnelGreat Firewall, Russian DPI, Iranian throttles, active probingVLESS+REALITY, Shadowsocks-2022, Hysteria, Trojan, Tor + obfs4/WebTunnelCategory 3 below

Pick by goal, not by name. A “VPN” doesn’t help against the GFW. A “proxy” (HTTP/SOCKS) doesn’t give you Tor’s anonymity. An obfuscated proxy gets you past censorship but doesn’t make you anonymous to the destination. These three categories aren’t interchangeable.

Also worth knowing: these tools compose. Tor-over-WireGuard, VLESS-over-VPN, Snowflake-as-Tor-bridge, etc. are real deployment patterns when one tool’s threat model doesn’t cover everything. The right combination depends on which adversary you’re worried about; see Privacy Guides — Tor Overview for the decision tree on combining Tor with other transports.


Goal: Make it hard for the destination (and for any observer of one side of the conversation) to know who you are.

The right answer for most people is Tor Browser. It bundles Tor + a hardened Firefox + sane defaults; nothing in the section below replaces it. Use the manual setup below only when you need to route a non-browser application (a CLI tool, a desktop chat client, etc.) through Tor.

For threat-model fit, also see:

Default Tor (and the public Tor Browser config) connects directly to the Tor network. Anyone watching your traffic — your ISP, a workplace firewall, a hotel Wi-Fi capture portal — can tell you’re using Tor by the IPs you’re talking to. They can’t see what you’re doing, but the fact of Tor is visible.

Bridges are Tor relays that aren’t published in the public directory. Pluggable transports like obfs4 wrap the connection in random-looking bytes so it doesn’t fingerprint as Tor. With a bridge + obfs4, your ISP sees an unidentifiable encrypted connection to an unremarkable IP — not “this user is on Tor.”

When to pick this over Tor Browser alone:

  • You want Tor where Tor itself isn’t blocked but you’d rather not advertise it (workplace, hotel Wi-Fi, family ISP).
  • Tor is blocked from where you are and you need a transport that doesn’t look like Tor.
  • You’re routing CLI tools or non-browser apps through Tor and need the fact-of-Tor hidden too — Tor Browser only solves it for browsing.

Install:

Terminal window
brew install tor obfs4proxy

Get fresh obfs4 bridge lines from https://bridges.torproject.org/options. Pick obfs4, untick “IPv6”, solve the CAPTCHA, copy the 2–3 obfs4 ... lines. If the page is blocked, email bridges@torproject.org from a Gmail/Riseup address with the body get transport obfs4.

Edit $(brew --prefix)/etc/tor/torrc/opt/homebrew/etc/tor/torrc on Apple Silicon, /usr/local/etc/tor/torrc on Intel:

SocksPort 9050
Log notice file /opt/homebrew/var/log/tor/notices.log
DataDirectory /opt/homebrew/var/lib/tor
UseBridges 1
ClientTransportPlugin obfs4 exec /opt/homebrew/bin/obfs4proxy
Bridge obfs4 <IP:PORT> <FINGERPRINT> cert=<...> iat-mode=0
Bridge obfs4 <IP:PORT> <FINGERPRINT> cert=<...> iat-mode=0

Each Bridge line must stay on one physical line — line-wrapping in your editor breaks the parser. The Homebrew tor formula doesn’t always create the log directory, so make it first:

Terminal window
mkdir -p /opt/homebrew/var/log/tor
brew services start tor
tail -f /opt/homebrew/var/log/tor/notices.log

Success looks like this — a series of progress lines climbing to 100%:

Bootstrapped 1% (conn_pt): Connecting to pluggable transport
Bootstrapped 2% (conn_done_pt): Connected to pluggable transport
Bootstrapped 10% (conn_done): Connected to a relay
Bootstrapped 14% (handshake): Handshaking with a relay
Bootstrapped 30% (loading_status): Loading networkstatus consensus
Bootstrapped 75% (enough_dirinfo): Loaded enough directory info to build circuits
Bootstrapped 100% (done): Done

Ctrl-C to exit tail once you see the 100% line. Verify:

Terminal window
curl --socks5-hostname 127.0.0.1:9050 https://check.torproject.org/api/ip
# expected: {"IsTor":true,"IP":"<some Tor exit IP>"}

Use --socks5-hostname (not --socks5) so DNS resolution goes through Tor too — otherwise your ISP sees you looking up every hostname you visit, defeating the point. With env vars the equivalent is ALL_PROXY=socks5h://127.0.0.1:9050 — the h matters.

Bridges burn out — refresh every couple of weeks

Section titled “Bridges burn out — refresh every couple of weeks”

Public obfs4 bridges have a high mortality rate. Bridges from bridges.torproject.org are handed to thousands of users; popular ones get blocklisted, rate-limited, or quietly disappear. Symptoms:

  • Bootstrap stalls at Bootstrapped 30% (loading_status) for more than a couple of minutes — the bridge is reachable but the directory consensus download is failing. Classic burned-bridge signature.
  • Bootstrap fails between 10% and 25% with Proxy Client: unable to connect OR connection ... ("general SOCKS server failure") in the log — the bridge itself is dead.
  • Tor that worked fine last week suddenly doesn’t.

Fix: revisit https://bridges.torproject.org/options, get fresh obfs4 lines, replace the Bridge obfs4 ... lines in torrc, restart Tor. If obfs4 is broadly blocked from where you are, try Snowflake (WebRTC-based, much harder for a censor to enumerate) or WebTunnel (looks like plain HTTPS) — see Tor’s circumvention guide for the full per-transport breakdown.

Terminal window
sudo apt update
sudo apt install tor obfs4proxy

Edit /etc/tor/torrc with the same UseBridges / ClientTransportPlugin / Bridge block, but with ClientTransportPlugin obfs4 exec /usr/bin/obfs4proxy. Restart:

Terminal window
sudo systemctl restart tor
sudo journalctl -u tor -f # watch bootstrap

The same --socks5-hostname rule applies for verification.


Tor with a local Privoxy HTTP-proxy frontend

Section titled “Tor with a local Privoxy HTTP-proxy frontend”

Tor speaks SOCKS5 (a TCP-level proxy protocol, listens on 127.0.0.1:9050 by default). Many older applications, OS-level proxy GUIs, or CLI tools only know how to talk to an HTTP proxy, not SOCKS. Privoxy is a small local HTTP-to-SOCKS5 bridge — it listens on 127.0.0.1:8118, accepts HTTP-proxy requests, and forwards them through Tor.

This is what the per-OS setup below does. It is not a substitute for Tor Browser for web browsing — Firefox/Chrome configured to use 127.0.0.1:8118 will leak DNS, WebRTC, and fingerprintable headers in ways Tor Browser specifically blocks. Use this pattern for:

  • Non-browser tools that want an HTTP proxy
  • OS-wide proxy configuration on devices that don’t have a Tor client (older iOS, locked-down Android, etc.)
  • Remote-access bridging (SSH-tunneled HTTP proxy)
Terminal window
brew install tor privoxy

Edit Privoxy’s config (/opt/homebrew/etc/privoxy/config on Apple Silicon, /usr/local/etc/privoxy/config on Intel) and add the forward rule that sends everything through Tor’s SOCKS5 port:

forward-socks5t / 127.0.0.1:9050 .

Start both services:

Terminal window
brew services start tor
brew services start privoxy

Point macOS at Privoxy under System Settings → Network → (your interface) → Details → Proxies → enable both Web Proxy (HTTP) and Secure Web Proxy (HTTPS), set host 127.0.0.1 and port 8118. Apply.

Verify: open http://check.torproject.org in a non-Tor-Browser window — it should say “Congratulations. This browser is configured to use Tor” if and only if the rest of the browser doesn’t bypass the proxy (Safari respects the system setting; Firefox/Chrome may use their own).

Terminal window
sudo apt update
sudo apt install tor privoxy

Edit /etc/privoxy/config and add:

forward-socks5t / 127.0.0.1:9050 .

Enable both services:

Terminal window
sudo systemctl enable --now tor privoxy

For per-application HTTP proxying:

Terminal window
export http_proxy=http://127.0.0.1:8118
export https_proxy=http://127.0.0.1:8118
curl -L https://check.torproject.org # should resolve to a Tor exit node

For system-wide GUI proxying, set it under your DE’s network settings (GNOME: Settings → Network → Network Proxy; KDE: System Settings → Network → Proxy).

If Privoxy + Tor runs on a server and you want to use it from a remote machine, don’t expose port 8118 to the internet. Open-relay HTTP proxies are scanned for and abused within hours. Use an SSH local-port-forward instead:

Terminal window
ssh -L 8118:localhost:8118 user@your-tor-host

Then on the local machine, point HTTP proxy settings at 127.0.0.1:8118. The proxy traffic is encrypted by SSH between the two machines, and the HTTP-proxy port stays bound to localhost on the server.

For iOS/Android/Windows: same idea — install an SSH client that supports local port forwarding (Termius, ConnectBot, PuTTY), forward 8118:localhost:8118, set the device’s Wi-Fi proxy to 127.0.0.1:8118.


Goal: Carry your traffic through a single relay you trust, encrypted from your device to that relay.

This is not the right tool for state-level censorship circumvention (the GFW blocks commercial-VPN IP ranges in bulk) and it is not the right tool for anonymity (the VPN provider sees everything Tor would otherwise hide). It is the right tool for: hiding your traffic from your ISP, hiding your home IP from destinations, defeating geo-blocks, and connecting to a private network.

Where to go:

  • VPN Recommendation — the user-facing pick-a-VPN guide. Mullvad, IVPN, Tor-over-VPN, multi-hop chains, self-hosted WireGuard.
  • WireGuard in Containers — the kernel/container-side hardening reference for self-hosted WireGuard.
  • Self-host Cloudflare Tunnels — the inverse pattern: pull traffic to your home network through a CF-fronted tunnel without exposing ports.

Category 3 — Censorship-circumvention / obfuscated proxies

Section titled “Category 3 — Censorship-circumvention / obfuscated proxies”

Goal: Get past an active censor that’s actively probing your endpoint, fingerprinting your traffic, and trying to distinguish your tunnel from normal HTTPS.

This is the tool you reach for in mainland China, Iran, Russia (intermittently), Myanmar, Turkmenistan, and similar environments. It is not a VPN. It is not for privacy. It is for staying connected when something actively wants you not to be.

Where to go:

  • VLESS / Xray Deployment Guide — the canonical IrregularChat write-up. Server-side deployment, REALITY config, hardening checklist, supply-chain caveats.
  • Cybersecurity Tools — the operator-facing tools section. Future Sing-box / Shadowsocks / Hysteria guides will land there.

Tools in this category (community guides not yet written for most; upstreams linked):

ToolUpstreamDistinguishing feature
VLESS + REALITY (Xray-core)XTLS/Xray-coreDesigned to resist active probing by forwarding unauthenticated probes to a real third-party TLS site. The community-converged default for state-level circumvention as of mid-2026 — also implemented independently by Sing-box and used by default in Hiddify. Not unconditionally undetectable — see active-probe vs. traffic-analysis caveats and citations in the IrregularChat deployment guide.
Sing-boxSagerNet/sing-boxIndependent reimplementation of VLESS, Shadowsocks, Hysteria, and Trojan in one binary. The “swap-in if Xray-core implodes” plan.
Shadowsocks-2022Shadowsocks-NET/shadowsocks-rustOlder, lighter-weight obfuscated proxy. Multiple mature implementations.
Hysteriaapernet/hysteriaQUIC-based; designed for high-loss / heavily-shaped networks.
Trojan-GFWtrojan-gfw/trojanPure TLS-mimicry; older but still deployed.
Tor pluggable transportsobfs4, WebTunnel, Snowflake (separate transports, all bundled with Tor / Tor Browser)Tor Project — circumventionAdd circumvention to Tor’s anonymity. The right answer when you need both at once. Snowflake in particular uses peer-to-peer WebRTC volunteers as ephemeral bridges.

For the governance / supply-chain risk discussion behind the VLESS-class tools, see the VLESS Investigation Field Notes series.


Ask one question first: what’s actively trying to stop you?

  • My ISP and the destination shouldn’t know what I’m doingTor Browser (category 1).
  • I want to look like I’m in a different country / hide my home IP from destinationscommercial VPN (category 2), see VPN Recommendation.
  • I need to connect to my own home network from outsideself-hosted WireGuard (category 2), see WireGuard in Containers.
  • I’m inside the Great Firewall / Iranian filter / Russian DPIVLESS+REALITY or Sing-box (category 3), see VLESS / Xray Deployment Guide.
  • I’m doing high-stakes journalism / dissident work in a hostile countryTor with pluggable transports (categories 1+3 combined), see the Tor circumvention guide.
  • Some random app wants an HTTP proxy and I want it routed through TorPrivoxy + Tor (category 1, recipe above).

If none of these fit, your threat model probably needs a more careful look than a proxy can solve — see Personal Threat Modeling first.