A self-hosted Tor SOCKS proxy in Docker, with a native macOS menu-bar toggle — no VPN kernel extension, no sudo, no routing-table hacks.
Run Tor locally in a container, flip it on/off from your menu bar like a VPN, and optionally benchmark public obfs4 bridges by real measured throughput (not just ping) if your network blocks Tor outright.
Tor Browser is great, but it only tunnels itself. If you want a system-level Tor SOCKS proxy for macOS you can toggle for any proxy-aware app — curl, git, Safari, Chrome, dev tools — without installing a VPN app, granting a system extension, or running Tor as an unsandboxed native process, this is that.
What it deliberately does not do: touch routing tables, create utun interfaces, or write pf rules. Those operate at the kernel network-stack level and can leave a Mac's network driver in a bad state if something goes wrong mid-change. Instead, tor-vpn-on.sh flips the same macOS SOCKS proxy system preference you'd set by hand in System Settings → Network → Proxies — fully reversible, no sudo, no persistent interface changes.
Tradeoff: only apps that honor the OS SOCKS proxy setting get routed through Tor (Safari, Chrome, most CLI tools, many apps). Firefox-family browsers (Firefox, Zen, etc.) maintain their own independent proxy config and need to be set up separately. Apps with fully hardcoded networking won't be covered. That's the deliberate cost of staying out of the kernel network layer.
| Component | What it does |
|---|---|
docker-compose.yml + tor/Dockerfile |
Tor + lyrebird (obfs4 pluggable transport) in a minimal Alpine container, SOCKS proxy on 127.0.0.1:9050 |
vpn/tor-vpn-on.sh / tor-vpn-off.sh |
Toggle the macOS system SOCKS proxy on/off, auto-detects your active network interface |
vpn/ (SwiftUI source) + build.sh |
Builds a native macOS menu-bar app (TorVPN.app) — no Xcode project required, just swiftc |
tor/bridges.sh |
Optional: benchmarks public obfs4 bridges by real download throughput (not just TCP ping) and switches to the fastest ones — only useful if Tor itself is blocked/throttled on your network |
git clone https://github.com/HalalifyMusic/tor-vpn-macos.git
cd tor-vpn-macos
./setup.shThis builds and starts the Tor container, verifies it's reachable, builds TorVPN.app, and offers to install it to /Applications.
Requirements: Docker Desktop, Xcode Command Line Tools (xcode-select --install), Python 3 (for icon generation, auto-installs Pillow).
Click the menu-bar icon → Enable. It sets 127.0.0.1:9050 as your system SOCKS proxy and verifies against check.torproject.org. Click Disable to revert — instantly, no reboot needed.
Most users don't need this — plain Tor works fine by default. If your ISP or country blocks Tor directly, you need an obfs4 bridge:
brew install bash # macOS ships bash 3.2, this needs bash 4+
/opt/homebrew/bin/bash tor/bridges.shThis pulls a public bridge list, TCP-latency-prefilters it, then actually bootstraps each surviving candidate in an isolated container and measures real download speed through it — keeping the fastest N. Takes a few minutes (bootstrapping + downloading a test file per candidate). Re-run periodically; public bridges rot.
Is this a real system-wide VPN?
No — see the "why this exists" tradeoff above. It's a SOCKS proxy toggle, not a routing-layer VPN. If you need true system-wide interception, look at Orbot (mobile) or the classic pf + TransPort transparent-proxy approach — both carry more kernel-network-stack risk than this project accepts.
Why not use tun2socks / a utun interface for real system-wide routing?
That's the standard approach and it works, but it means creating virtual network interfaces and rewriting the routing table — a botched cleanup (crash, sleep, forced quit) can leave your Mac in a confusing "no route to host" state until reboot, and interface-level networking bugs are a real (if rare) source of driver instability. This project chooses the OS-preference route specifically to avoid that risk class entirely.
Does Firefox/Zen work with this?
Not automatically — Firefox-based browsers ignore the macOS system proxy setting and need their own SOCKS config at about:config (network.proxy.socks → 127.0.0.1, network.proxy.socks_port → 9050, network.proxy.type → 1).
Why Alpine + lyrebird instead of obfs4proxy?
obfs4proxy was renamed/succeeded by lyrebird (Tor Project's own rewrite, protocol-compatible) and Alpine no longer packages the former.
MIT — see LICENSE.

