SOCKS5 Proxy Mode¶
SOCKS5 mode is the default and most flexible way to use r-vpn. It runs a local SOCKS5 proxy that individual apps can be pointed at — without affecting other traffic on your machine.
Starting the Proxy¶
Default listen address: 127.0.0.1:1080
Once running you'll see:
Configuring Apps¶
macOS — System-wide Proxy¶
System Settings → Network → your connection → Details → Proxies
Enable SOCKS Proxy and set:
- Server: 127.0.0.1
- Port: 1080
This routes all system traffic (Safari, curl, etc.) through the VPN.
Firefox¶
Settings → General → Network Settings → Manual proxy configuration
- SOCKS Host:
127.0.0.1 - Port:
1080 - Select SOCKS v5
- Check Proxy DNS when using SOCKS v5 to prevent DNS leaks (not needed if you have the DNS proxy enabled)
Chrome / Brave¶
Chrome uses the system proxy on macOS. On Linux, use the SwitchyOmega extension:
- Install SwitchyOmega
- Create a new profile → Protocol: SOCKS5, Server:
127.0.0.1, Port:1080 - Switch to that profile when you want to use the VPN
curl¶
Linux — System-wide (environment variables)¶
export ALL_PROXY=socks5://127.0.0.1:1080
export HTTPS_PROXY=socks5://127.0.0.1:1080
export HTTP_PROXY=socks5://127.0.0.1:1080
Add to ~/.bashrc or ~/.zshrc to persist across sessions.
HTTP Proxy¶
r-vpn can also run as an HTTP proxy alongside the SOCKS5 proxy. This is useful when apps or environments expect HTTP_PROXY/HTTPS_PROXY environment variables pointing at an HTTP proxy (the most common convention for CLI tools like curl, git, npm, pip, and Docker).
Both proxies share the same WebSocket connection pool — running both simultaneously adds zero overhead.
Enable the HTTP Proxy¶
Restart the client — you should see:
Using Environment Variables¶
The most common way to use the HTTP proxy is via environment variables. Most CLI tools and programming languages respect these automatically:
export HTTP_PROXY=http://127.0.0.1:8118
export HTTPS_PROXY=http://127.0.0.1:8118
export ALL_PROXY=http://127.0.0.1:8118
After setting these, tools like curl, git, npm, pip, wget, and Docker route through the VPN without any per-app configuration:
# No --proxy flag needed — env vars are picked up automatically
curl https://api.ipify.org
git clone https://github.com/user/repo.git
pip install requests
Add to ~/.bashrc or ~/.zshrc to persist across sessions.
curl (explicit)¶
How It Works¶
The HTTP proxy handles two request types:
- HTTP CONNECT — used for HTTPS. The client sends
CONNECT host:443 HTTP/1.1, the proxy responds with200 Connection Established, and traffic flows through an encrypted tunnel to the destination. - Plain HTTP forwarding — used for unencrypted HTTP. The client sends
GET http://host/path HTTP/1.1, the proxy connects to the host and forwards the request.
Both paths are split-tunnel-aware and use the same connection pool as SOCKS5.
Authentication¶
To require Basic authentication:
[http_proxy]
enabled = true
listen_address = "127.0.0.1:8118"
auth_enabled = true
auth_username = "user"
auth_password = "changeme"
Clients must send Proxy-Authorization: Basic ... header (browsers and curl -x handle this automatically when credentials are in the URL: http://user:pass@127.0.0.1:8118).
SOCKS5 vs HTTP Proxy¶
| SOCKS5 | HTTP Proxy | |
|---|---|---|
| Protocols | Any (TCP + UDP) | HTTP and HTTPS only |
| Environment variables | ALL_PROXY=socks5://... |
HTTP_PROXY=http://... |
| Browser support | Native on macOS/Firefox | Universal (all browsers) |
| CLI tool support | Some tools (curl, Node) | Most tools (curl, git, pip, npm, Docker) |
| Authentication | SOCKS5 username/password | HTTP Basic auth |
| Best for | Per-app routing, UDP | System-wide env vars, CI/CD |
In most cases, use the HTTP proxy with environment variables — it has the broadest compatibility with CLI tools and build systems. Use SOCKS5 for per-app routing or when you need UDP support.
Split Tunneling¶
Split tunneling lets you route only certain traffic through the VPN while the rest connects directly. This is useful when you want to reach blocked sites through the VPN while keeping local network and domestic traffic unaffected.
Built-in China bypass¶
Enable split tunneling with automatic China IP bypass in client.toml:
When enabled, traffic to Chinese IPs (based on APNIC data — ~8800 networks) connects directly, and everything else routes through the VPN.
Custom bypass networks¶
bypass-networks.txt — one CIDR per line:
Ad blocking¶
Blocks known ad and tracker domains at the DNS level. No bytes sent, no connection established.
DNS Proxy¶
Important: Without the DNS proxy, your DNS queries may leak to your ISP even when using the SOCKS5 proxy. See DNS Leak Prevention for a complete explanation.
By default, DNS queries are resolved by your system's DNS server — outside the VPN tunnel. This means your ISP can observe which domains you look up even while your traffic is proxied.
r-vpn includes a built-in DNS proxy that resolves all queries server-side through the same encrypted WebSocket tunnel. It is also split-tunnel aware: bypass domains are resolved locally, and blocked ad/tracker domains return NXDOMAIN immediately without ever hitting the network.
Enable the DNS proxy¶
Note: Port 53 requires root or
CAP_NET_BIND_SERVICE. Use port5353for unprivileged testing (see below).
Restart the client — you should see:
macOS — system-wide¶
Run the client with sudo (so it can bind port 53), then add 127.0.0.1 as your DNS server:
System Settings → Network → your connection → Details → DNS → + → 127.0.0.1
Or via the command line (replace Wi-Fi with your interface name):
To restore the original DNS when you're done:
Linux — system-wide¶
Run the client as root (or with the CAP_NET_BIND_SERVICE capability) with listen_address = "127.0.0.1:53", then point your resolver at it.
/etc/resolv.conf (direct):
systemd-resolved — add to /etc/systemd/resolved.conf:
sudo systemctl restart systemd-resolved
Unprivileged testing (port 5353)¶
Verify it works:
The response will come from your VPN server rather than your local ISP.
Connection Modes¶
The SOCKS5 proxy supports two connection modes to the server:
Standard Mode (Default, Recommended)¶
Each SOCKS5 flow opens its own separate WebSocket connection with its own X3DH handshake and DoubleRatchet. This is the recommended mode.
Why this is the default: - Traffic pattern matches standard tools — each connection is an independent WebSocket, similar to normal HTTPS browsing - Short-lived connections are harder for traffic classifiers to identify and block - Simpler failure isolation — one connection dropping doesn't affect others
Multiplexed Mode (Optional)¶
All SOCKS5 flows share a single WebSocket connection with one shared DoubleRatchet session. Each SOCKS5 CONNECT creates a logical "flow" via CreateFlow/CloseFlow control messages over the same tunnel.
Benefits: - Single TLS handshake, single X3DH key exchange — ~250ms overhead vs ~600ms per-connection - 0-RTT flow creation — data is sent immediately without waiting for server ACK - Lower server resource usage (one WebSocket, one ratchet vs one per flow) - Server supports up to 2000 concurrent flows per mux session - 100% success rate in stress tests (vs ~85% for standard mode)
Trade-offs: - A single long-lived binary stream is a distinctive traffic pattern that classifiers can detect - All flows share one connection — if it drops, everything reconnects
How it works:
1. First SOCKS5 CONNECT opens the mux WebSocket tunnel ({server_path}/mux)
2. Performs X3DH handshake to establish the shared DoubleRatchet
3. Subsequent flows send CreateFlow control messages over the same tunnel
4. Client sends data immediately (0-RTT) — server buffers while connecting to target
5. Data flows through multiplexed frames
Security: The 0-RTT optimization is NOT TLS 0-RTT. The TLS handshake and X3DH key exchange are complete before any data flows. Replay protection is provided by the Double Ratchet — each message has a unique message_number, and the ratchet rejects messages with number < current (see ratchet.rs:decrypt). Message keys are consumed after use, so replays fail with "Message too old".
Configuration:
To override the mux endpoint explicitly:
Comparing Modes¶
| Standard | Multiplexed | |
|---|---|---|
| WebSockets per session | 1 per flow | 1 |
| X3DH handshakes | 1 per flow | 1 |
| Server flows | Unlimited | Up to 2000 |
| Server-side WS connections | N | 1 |
| Traffic pattern | Normal HTTPS-like | Single long-lived stream |
| Success rate (HK, 15min) | ~85% | 100% |
| Latency p50 (HK) | ~575ms | ~315ms |
| Latency p95 (HK) | ~2000ms | ~1060ms |
| Best for | DPI evasion, traffic blending | Reliability, high throughput |
Note: Standard mode opens one WebSocket per TCP flow. On busy networks (e.g. browsers with many tabs), this can exhaust the server's
max_connections_per_iplimit. If needed, increase the server's rate limits:
Changing the Listen Address¶
To listen on a specific interface (e.g. to share the proxy with other devices on your local network):
Security note: Only expose the SOCKS5 port on trusted networks. There is no authentication by default.
To add authentication:
[socks5]
listen_address = "0.0.0.0:1080"
auth_enabled = true
auth_username = "user"
auth_password = "changeme"
Running as a Service¶
Linux (systemd)¶
[Unit]
Description=r-vpn Client
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=YOUR_USER
ExecStart=/usr/local/bin/rvpn -c /etc/rvpn/client.toml
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
FreeBSD (rc.d)¶
Create /usr/local/etc/rc.d/rvpn_client: