A transparent VPN that routes all system traffic through the Tor network.
Implemented in Go — designed for Windows first, Linux-compatible with no code changes.
┌─────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Your app │───▶│ TUN device │───▶│ Tor proxy │───▶│ Tor Network │
│ (any OS) │ │ torvpn │ │ 127.0.0.1 │ │ → Internet │
└─────────────┘ └──────────────┘ │ :9050/8118 │ └──────────────┘
└──────────────┘
▲
┌────┴────────┐
│ DoH Resolver│ ← All DNS goes here (no leaks)
│ 127.0.0.1 │ then through Tor to 1.1.1.1
│ :5300 │
└─────────────┘
- Architecture
- Prerequisites — Windows
- Prerequisites — Linux
- Building
- Running on Windows
- Running on Linux
- Docker (Linux)
- Speed Tuning & torrc
- Using Bridges (obfs4)
- Troubleshooting
- Security Notes
- Project Structure
| Component | File | Responsibility |
|---|---|---|
| Main | cmd/torvpn/main.go |
Wires all components together, signal handling |
| Tor Controller | internal/tor/controller.go |
Spawns Tor, monitors bootstrap, sends NEWNYM |
| Circuit Manager | internal/circuit/manager.go |
Periodic rotation, relay scoring by bandwidth |
| DNS Resolver | internal/dns/server.go |
Leak-proof DNS via DoH through Tor |
| TUN Device | internal/tun/device.go |
Packet I/O, SOCKS5 forwarding |
| Windows TUN shim | internal/tun/tun_windows.go |
netsh, WinTUN wiring |
| Linux TUN shim | internal/tun/tun_linux.go |
ip addr/route, kernel TUN |
DNS query (UDP/53)
→ TUN → redirected to 127.0.0.1:5300
→ DoH (HTTPS) → Tor SOCKS5 → 1.1.1.1 → answer
TCP connection
→ TUN → SOCKS5 dial through Tor → remote server
UDP (non-DNS)
→ TUN → best-effort SOCKS5 forwarding (most Tor exits are TCP only)
ICMP
→ dropped (Tor cannot carry ICMP)
Download from https://go.dev/dl/ and install.
Verify: go version
- Download Tor Expert Bundle from https://www.torproject.org/download/tor/
- Extract the ZIP.
- Add the extracted folder to your system
PATH:- Open Environment Variables → user variables for user → PATH → EDIT → NEW
- Add the full path (e.g.
\tor\)
- Verify: open cmd and type
tor --version - download obfs4proxy.exe
- and paste
obfs4proxy.exefile to the/tor/path next totor.exe. - add
tor.exeandobfs4proxy.exeon firewall.
- Download
wintun-x86_64-*.zipfrom https://www.wintun.net/ - Extract
wintun.dll(64-bit version) into thetorvpndirectory (or into a folder in yourPATH).
WinTUN is the same driver WireGuard uses on Windows — it is stable and well-maintained.
Required for wintun.dll. Download from Microsoft if you see DLL errors.
sudo apt update
sudo apt install -y tor iproute2 golang-go
# For obfs4 bridges (optional):
sudo apt install -y obfs4proxysudo dnf install -y tor iproute golangsudo pacman -S tor iproute2 gowget https://go.dev/dl/go1.22.0.linux-amd64.tar.gz
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf go1.22.0.linux-amd64.tar.gz
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.profile
source ~/.profile
go version# Check if already loaded
ls /dev/net/tun
# If missing, load it:
sudo modprobe tun
# Make it load at boot:
echo "tun" | sudo tee /etc/modules-load.d/tun.confClone and build from either OS:
# Clone
https://github.com/KHOSROW-II/torVPN.git
cd torvpn
# Download Go dependencies
go mod download
go mod tidy
# Build for current OS
go build -ldflags="-s -w" -o torvpn ./cmd/torvpn/
# Windows: produces torvpn.exe
# Linux: produces ./torvpn
# Cross-compile from Linux → Windows:
GOOS=windows GOARCH=amd64 go build -o torvpn.exe ./cmd/torvpn/
# Cross-compile from Windows → Linux (in PowerShell):
$env:GOOS="linux"; $env:GOARCH="amd64"; go build -o torvpn ./cmd/torvpn/# Option A: PowerShell script (auto-elevates, checks deps, builds & runs)
.\scripts\start_windows.ps1
# Option B: Batch file
.\scripts\start_windows.bat
# Option C: Manual (from an Administrator terminal)
go run ./cmd/torvpn/ -verboseMust be run as Administrator. WinTUN requires Administrator to create the virtual network adapter.
On first run, Windows Firewall may ask to allow torvpn.exe — click Allow access.
# Check your exit IP — should be a Tor exit node
Invoke-WebRequest -Uri "https://check.torproject.org/api/ip" | Select-Object -ExpandProperty Content
# Check for DNS leaks
Invoke-WebRequest -Uri "https://dnsleaktest.com" -UseBasicParsingafter run vpn you can connect to HTTP proxy:
127.0.0.1:8118and SOCKS proxy:127.0.0.1:9050
# Make script executable (once)
chmod +x scripts/start_linux.sh
# Run as root
sudo ./scripts/start_linux.sh
# Or manually:
sudo ./torvpn -torrc configs/torrc -tun torvpn0 -ip 10.0.0.1/24 \
-dns 127.0.0.1:5300 -socks-port 9050 -verboseThe Linux script automatically:
- Backs up
/etc/resolv.confand points DNS at127.0.0.1 - Restores
/etc/resolv.confon Ctrl+C / exit - Loads the
tunkernel module if needed
# Check your exit IP
curl https://check.torproject.org/api/ip
# Full DNS leak test
curl https://ipleak.net/json/
# Confirm traffic is going through TUN
ip route show | grep torvpn0after run vpn you can connect to HTTP proxy:
127.0.0.1:8118and SOCKS proxy:127.0.0.1:9050
# Build image
docker build -t torvpn .
# Run (requires TUN device and NET_ADMIN)
docker run --rm \
--cap-add=NET_ADMIN \
--device /dev/net/tun \
-p 9050:9050 \
torvpn
# With custom torrc mounted in
docker run --rm \
--cap-add=NET_ADMIN \
--device /dev/net/tun \
-v $(pwd)/configs/torrc:/etc/torvpn/torrc:ro \
torvpnTor is inherently slower than a regular VPN due to 3-hop onion routing. These tunings minimize unnecessary latency:
| Parameter | Default | Effect |
|---|---|---|
CircuitBuildTimeout |
10 |
Give up on slow circuit builds faster |
NewCircuitPeriod |
30 |
Build spare circuits proactively |
MaxCircuitDirtiness |
600 |
Rotate after 10 min (balance freshness/overhead) |
MaxClientCircuitsPending |
16 |
More parallel build attempts |
NumEntryGuards |
3 |
More guard diversity |
KeepalivePeriod |
60 |
Prevent NAT expiry on idle |
Tor automatically selects relays weighted by bandwidth. The circuit.Manager in TorVPN additionally:
- Fetches relay data from the Onionoo API
- Scores relays:
bandwidth × stability_multiplier - Logs the top relays for observability
You can bias selection further with torrc:
# Prefer relays in specific countries (faster for your region)
EntryNodes {DE},{NL},{CH}
StrictNodes 0 # 0 = fall back if unavailable; 1 = strict
# Exclude known-slow or unreliable exits
ExcludeExitNodes {RU},{CN},{IR}
# Linux: measure time to get a response via TorVPN
time curl -s https://check.torproject.org/api/ip
# Compare without TorVPN (stop it first)
time curl -s https://api.ipify.orgTypical Tor latency: 300–600ms additional per hop. HTTP/2 and connection keep-alive significantly help.
- If your ISP throttles or blocks Tor, use obfs4 bridges:
- But if the process still doesn't progress or is extremely slow, you can change the path of the config/torrc configuration file in the folders and remove the hashtags from lines 83 to 87.
# Debian/Ubuntu
sudo apt install obfs4proxy
# Windows: download obfs4proxy.exe from
# https://github.com/Yawning/obfs4/releases
# Place next to tor.exeVisit https://bridges.torproject.org/ → select obfs4 → get lines like:
obfs4 192.0.2.1:443 FINGERPRINT cert=XXXX iat-mode=0
UseBridges 1
ClientTransportPlugin obfs4 exec /usr/bin/obfs4proxy
Bridge obfs4 192.0.2.1:443 FINGERPRINT cert=XXXX iat-mode=0
Bridge obfs4 192.0.2.2:8080 FINGERPRINT cert=YYYY iat-mode=0
You need at least 2 bridge lines for reliability.
Windows:
- Ensure
wintun.dllis next totorvpn.exe - Run as Administrator
- Check Windows Event Viewer for driver errors
- Reinstall WinTUN if needed: https://www.wintun.net/
Linux:
sudo modprobe tun
ls -la /dev/net/tun # should show crw-rw-rw-
sudo setcap cap_net_admin+eip ./torvpn # alternative to running as root- Tor can take 2–3 minutes on a slow connection — increase
-torrctimeout - Check if Tor is blocked by your firewall:
telnet 5.9.158.75 9001 - Enable obfs4 bridges (see above)
- Check your
configs/torrcfor syntax errors:tor -f configs/torrc --verify-config
- Windows: Ensure
tor.exeis in PATH or in the current directory - Linux:
which torshould return a path; install if missing - Test manually:
tor -f configs/torrc
- you can type this
go build -ldflags="-s -w" -buildvcs=false -o torvpn.exe ./cmd/torvpn/or - run with
.\scripts\start_windows.bat
- Verify TorVPN's DNS resolver is running:
nc -u 127.0.0.1 5300(send a query) - On Linux, check
/etc/resolv.confpoints to127.0.0.1 - On Windows, verify the adapter's DNS is set to
127.0.0.1 - Check for
systemd-resolvedoverriding DNS:sudo systemctl stop systemd-resolved
The Onionoo relay fetch downloads ~1 MB of data every 30 minutes. To disable:
Set FetchUselessDescriptors 0 in torrc (already the default) and reduce relay refresh in circuit/manager.go:
relayTicker := time.NewTicker(4 * time.Hour) // was 30 minutes> netsh interface ip set address name="..." static ...
- Ensure you're running as Administrator
- The WinTUN adapter may not be visible until TorVPN has started once
- Check adapter name in Device Manager
- If the bootstrap process timed out, just rerun the project because the process is saved.
Windows:
route delete 0.0.0.0 mask 128.0.0.0
route delete 128.0.0.0 mask 128.0.0.0Linux:
sudo ip route del 0.0.0.0/1 dev torvpn0
sudo ip route del 128.0.0.0/1 dev torvpn0
sudo ip rule del fwmark 0x1 lookup mainCheck the control password matches in both torrc (HashedControlPassword) and the flag (-control-pass). Regenerate the hash:
tor --hash-password "yournewpassword"
# Copy the output (16:...) into HashedControlPassword in torrc- This software does not provide anonymity on its own. Application-level identifiers (cookies, logged-in accounts, WebRTC, etc.) can still de-anonymize you.
- The
HashedControlPasswordin the defaulttorrcis public. Change it before using TorVPN on a shared or production system. - Tor's SOCKS5 proxy (
127.0.0.1:9050) is bound to localhost only and not exposed to the network. - The DNS resolver (
127.0.0.1:5300) is also localhost-only. - UDP (non-DNS) traffic has limited Tor support. Most Tor exits are TCP-only. UDP will either be dropped or carried via TCP tunnelling with overhead.
- ICMP (ping) is always dropped — this is expected behaviour.
torvpn/
├── cmd/
│ └── torvpn/
│ └── main.go ← Entry point, flag parsing, wiring
├── internal/
│ ├── circuit/
│ │ └── manager.go ← Circuit rotation, relay scoring
│ ├── dns/
│ │ └── server.go ← Leak-proof DoH resolver
│ ├── tor/
│ │ └── controller.go ← process, connects to its control port, polls bootstrap progress
│ └── tun/
│ ├── device.go ← TUN I/O, packet forwarding
│ ├── tun_windows.go ← Windows: WinTUN, netsh (build tag: windows)
│ └── tun_linux.go ← Linux: /dev/net/tun, ip (build tag: linux)
├── configs/
│ └── torrc ← Performance-tuned torrc (auto-generated if absent)
├── scripts/
│ ├── start_windows.bat ← Windows batch launcher
│ ├── start_windows.ps1 ← Windows PowerShell launcher (auto-elevates)
│ └── start_linux.sh ← Linux bash launcher (handles DNS + cleanup)
├── Dockerfile ← Multi-stage Linux container
├── go.mod
└── README.md
MIT — see LICENSE file.