Skip to content

Client Configuration Reference

Complete reference for all fields in client.toml.


FieldTypeDefaultDescription
server_addressstring"wss://localhost:443/api/v1/ws"Full WebSocket URL of the server. Must include scheme (wss://), hostname, port, and path.
sni_hostnamestring(from URL)Override the TLS SNI hostname sent during the handshake. Useful when connecting by IP address or CDN.
identity_key_filepath"identity.key"Path to your client identity key. Generated with rvpn keygen.
prekey_bundlepath(none)Path to the server’s prekey-bundle.json. Required for first-time setup.
server_public_keystring(none)Hex-encoded server public key. Alternative to prekey_bundle when you only have the raw key.
tls_fingerprintstring"chrome"TLS ClientHello fingerprint to mimic. Options: "chrome", "firefox", "safari", "none". Use "chrome" for best DPI resistance.
data_dirpath(platform default)Directory for runtime data (known hosts, stats). Defaults to ~/.local/share/rvpn/ on Linux, ~/Library/Application Support/rvpn/ on macOS.

SOCKS5 proxy settings. These only apply when running in SOCKS5 mode (the default).

FieldTypeDefaultDescription
listen_addressstring"127.0.0.1:1080"Address and port to accept SOCKS5 connections on. Use "0.0.0.0:1080" to share the proxy with other devices on your network.
udp_associatebooltrueEnable SOCKS5 UDP ASSOCIATE command (for UDP-based apps).
auth_enabledboolfalseRequire username/password authentication for SOCKS5 clients.
auth_usernamestring(none)Username when auth_enabled = true.
auth_passwordstring(none)Password when auth_enabled = true.
multiplexboolfalseUse a single multiplexed WebSocket for all connections. When enabled, uses 0-RTT flow creation for lower latency. Default false — one WebSocket per connection creates a traffic pattern that blends in with normal browsing. See Connection Modes.
mux_pathstring(auto)Override the mux WebSocket endpoint path. Only used when multiplex = true. Defaults to {server_path}/mux.
[socks5]
listen_address = "127.0.0.1:1080"
auth_enabled = true
auth_username = "alice"
auth_password = "hunter2"

HTTP/HTTPS proxy that runs alongside the SOCKS5 proxy. Disabled by default. Enables use of HTTP_PROXY/HTTPS_PROXY environment variables for system-wide or per-tool VPN routing. Both proxies share the same connection pool — running both simultaneously adds zero overhead.

Handles two request types:

  • HTTP CONNECT — used for HTTPS. The client sends CONNECT host:443 HTTP/1.1, the proxy establishes an encrypted tunnel to the destination.
  • Plain HTTP forwarding — used for unencrypted HTTP. The proxy connects to the host and forwards the request.

Both paths are split-tunnel-aware and use the same multiplexed WebSocket tunnel as SOCKS5.

FieldTypeDefaultDescription
enabledboolfalseStart the HTTP proxy alongside the SOCKS5 proxy.
listen_addressstring"127.0.0.1:8118"Address and port to accept HTTP proxy connections on.
auth_enabledboolfalseRequire Basic authentication for HTTP proxy clients.
auth_usernamestring(none)Username when auth_enabled = true.
auth_passwordstring(none)Password when auth_enabled = true.
multiplexboolfalseUse a single multiplexed WebSocket. Default false is recommended — see Connection Modes.
mux_pathstring(auto)Override the mux WebSocket endpoint path. Only used when multiplex = true. Defaults to {server_path}/mux.
[http_proxy]
enabled = true
listen_address = "127.0.0.1:8118"

With authentication:

[http_proxy]
enabled = true
listen_address = "127.0.0.1:8118"
auth_enabled = true
auth_username = "user"
auth_password = "changeme"

See HTTP proxy setup for usage with environment variables and per-app configuration.


Routes DNS queries through the encrypted tunnel to prevent DNS leaks in SOCKS5 mode. Disabled by default.

When enabled, the client listens for UDP DNS queries on listen_address and forwards them to the server’s /dns WebSocket endpoint using the same X3DH + Double Ratchet encryption as regular traffic. Split tunnel rules are respected: bypass domains are resolved locally and blocked ad/tracker domains return NXDOMAIN immediately.

FieldTypeDefaultDescription
enabledboolfalseStart the local DNS proxy alongside the SOCKS5 proxy.
listen_addressstring"127.0.0.1:5353"UDP address and port for the DNS proxy. Use port 53 for system-wide compatibility (requires root or CAP_NET_BIND_SERVICE).
nameserverslist["223.5.5.5:53", "1.1.1.1:53", "8.8.8.8:53"]Public DNS servers used for bypass domains. Queries are sent directly via UDP to avoid looping back to the DNS proxy itself. CN users should put a local DNS first (e.g. 119.29.29.29:53).
[dns_proxy]
enabled = true
listen_address = "127.0.0.1:53"
nameservers = ["223.5.5.5:53", "1.1.1.1:53", "8.8.8.8:53"]

See DNS proxy setup for instructions on pointing your system DNS at this address.


TUN interface settings. Enable TUN mode by setting enabled = true. The client IP address, gateway IP, and DNS servers are assigned dynamically by the server via the VirtualIp message — do not set them manually.

FieldTypeDefaultDescription
enabledboolfalseEnable full tunnel (TUN) mode. All IP traffic is routed through the VPN.
interface_namestring(auto)TUN interface name. Omit to let the OS assign one — typically utun0 on macOS and tun0 on Linux/FreeBSD. Set to a specific name if you need one for firewall rules.
routeslist["0.0.0.0/0"]Routes to send through the tunnel. Default routes all traffic. Specify individual CIDRs for split-routing.
mtuinteger1420MTU of the TUN interface. Lower values reduce fragmentation on high-latency links.
[tun]
enabled = true
# interface_name = "vpn0" # optional, defaults to OS-assigned name
mtu = 1420
routes = ["0.0.0.0/0"]

Controls which traffic bypasses the VPN and which is forced through it.

FieldTypeDefaultDescription
enabledboolfalseEnable split tunneling. Must be true for any other split tunnel settings to take effect.
builtin_bypass_countrieslist["CN"]Country codes whose IP ranges are automatically bypassed. Uses APNIC data. Supported: "CN", "HK", "TW", "RU", and others. Set to [] to disable.
bypass_networks_filepath(none)Path to a file of CIDR networks (one per line) that connect directly, bypassing the VPN.
bypass_domains_filepath(none)Path to a file of domain names (one per line) that connect directly.
tunnel_networks_filepath(none)Path to a file of CIDR networks that are forced through the VPN (overrides bypass rules).
tunnel_domains_filepath(none)Path to a file of domain names forced through the VPN.
bypass_networkslist[]Inline list of CIDR networks to bypass. Same as bypass_networks_file but defined directly in the config.
auto_reload_intervalinteger86400How often (in seconds) to reload the bypass/tunnel files. Set to 0 to disable auto-reload.
block_adsboolfalseBlock known ad and tracking domains at the DNS level. No bytes sent to blocked domains.
ad_block_filepath(none)Path to a custom ad block list (one domain per line). Used in addition to the built-in list when block_ads = true.
[split_tunnel]
enabled = true
builtin_bypass_countries = ["CN"]
block_ads = true
bypass_networks_file = "~/.config/rvpn/bypass-networks.txt"

Client-side network behavior.

FieldTypeDefaultDescription
ipv6_enabledbooltrueEnable IPv6 connections through the proxy.
prefer_ipv4booltrueWhen both IPv4 and IPv6 are available, prefer IPv4. Reduces latency on most networks.
dns_cache_enabledbooltrueCache DNS responses to reduce repeated lookups.
dns_cache_ttlinteger14400How long (in seconds) to cache DNS entries. Defaults to 4 hours.
dns_cache_sizeinteger1000Maximum number of entries in the DNS cache.
dns_serverslist[]Custom upstream DNS nameservers for resolving bypass domains (direct connections). Queries are sent directly via UDP to these servers, bypassing the system resolver entirely. Leave empty to use the system default. Useful when the system resolver is unreliable or you want to use a specific DNS provider for China traffic.
[network]
prefer_ipv4 = true
dns_cache_enabled = true
dns_cache_ttl = 14400
dns_servers = ["223.5.5.5", "223.6.6.6"] # Alibaba DNS for CN bypass domains

Pins the server’s Ed25519 identity key (SSH-style TOFU) so the client refuses to connect if the server ever presents a different key. See Server Identity Pinning for the full model, including the operator rotation ceremony.

FieldTypeDefaultDescription
fingerprintstring(none)Expected pin in the canonical ik:1:<base32> form (e.g. ik:1:d4rgmp5b7ta6qmxi2mccwkjq4qxopfxzr7qivbfgu4wjycmuxnla). If set, the client rejects connections where the server’s identity doesn’t match. Legacy 32-character hex values from older installs are still accepted and rewritten on save.
trust_on_first_usebooltrueAccept any server identity on the first connection and pin it for future verification.
known_hosts_filepath"known_hosts.json"Where to store pinned server identities. Entries in the legacy hex format are migrated to ik:1:… on save, keeping the original first_seen timestamp.
strictbooltrueIf true, abort the connection on a mismatch. If false, only log a warning and continue.
strict_modeboolfalseStrict TOFU. If true, reject unknown server identities even on the first connection — you must set fingerprint explicitly before the first connect. Default false accepts and pins on first use.
[server_identity]
trust_on_first_use = true
strict = true

The CLI client can hold a small pool of servers and dispatch each SOCKS5 flow to one of them based on the target hostname or IP. Typical use case: default all traffic through Hong Kong, but send google.com (and friends) through Singapore so geolocated content resolves correctly on the Singapore side.

This feature is SOCKS5-only. TUN mode wraps the whole network stack in one tunnel and has no per-flow hook; enabling multi-server config in TUN mode is refused with a clear error. Multiplexed SOCKS5 (socks5.multiplex = true) is also refused, because the shared multiplex tunnel is single-server.

The client’s identity_key_file is shared across every server (SSH-model — one client key, many hosts). Each server has its own prekey bundle.

Zero or more extra servers can be declared with [[server]] blocks. The top-level server_address + prekey_bundle remain the implicit "default" server, so existing single-server configs keep working unchanged.

FieldTypeRequiredDescription
namestringyesSymbolic name used in [routing.<name>]. Must be unique; "default" is reserved.
addressstringyesWebSocket URL (wss://...).
prekey_bundlepathyesPath to this server’s X3DH prekey bundle JSON.
sni_hostnamestringnoTLS SNI override. Defaults to the URL host.
fingerprintstringnoPinned ik:1:... identity. Overrides the top-level [server_identity] for this server.

Routing rules keyed by server name. A SOCKS5 request is dispatched to the named server if any of its domains or ips match; otherwise it goes to the default server.

FieldTypeDescription
domainsarray of stringsHostname patterns — see the matching rules below. Case-insensitive.
ipsarray of stringsLiteral IPs (8.8.8.8) or CIDR blocks (1.1.1.0/24, 2606:4700::/32).

Three forms are supported. The distinction between google.com and *.google.com is important — they do different things.

PatternMatchesDoes NOT matchUse when
google.comgoogle.com and mail.google.com, www.google.com, …notgoogle.comYou want the apex and every subdomain (the common case).
*.google.commail.google.com, www.google.comgoogle.com itself — the apex is excluded on purposeYou want subdomains only, e.g. because the apex should follow a different rule.
google.com. (trailing dot)Only exactly google.comAny subdomainYou need a strict single-host match.

Wildcards other than a leading *. are rejected at startup — google.* or *.google.* are not valid.

Common gotcha: if you write *.google.com and then browse to https://google.com, the request goes to the default server, not the routed one. Use the bare google.com form to cover both the apex and subdomains.

Match order is hostname first, IP fallback. A SOCKS5 request with ATYP = 0x03 (domain) carries the raw hostname; the client sends that hostname unresolved through the chosen server, so DNS is done server-side and geo-DNS lookups return answers local to the chosen exit.

If your SOCKS5 client resolves DNS locally (e.g. curl -x socks5://… rather than socks5h://…, or a system-wide proxy setting), the request arrives with ATYP = 0x01 — a literal IP — and domain rules cannot match it. Either flip your client to hostname-passthrough mode (socks5h://) or add the destination IP ranges under ips.

server_address = "wss://hk.example.com"
identity_key_file = "identity.key"
prekey_bundle = "hk.bundle.json"
[[server]]
name = "sg"
address = "wss://sg.example.com"
prekey_bundle = "sg.bundle.json"
[routing.sg]
domains = ["google.com", "*.google.com", "youtube.com"]
ips = ["8.8.8.8/32", "1.1.1.1"]

With this config, curl -x socks5h://127.0.0.1:1080 https://google.com opens a WebSocket to the SG server and lets SG resolve google.com; everything else keeps going through HK.

If a routed server is unreachable, the SOCKS5 request fails — the client does not silently fall back to the default. That’s deliberate: geo-routed traffic returning from the wrong region is worse than a clean failure.


Tuning for high-throughput or resource-constrained environments.

FieldTypeDefaultDescription
worker_threadsinteger4Number of async worker threads. Increase on high-core servers.
recv_buffer_sizeinteger262144TCP receive buffer size in bytes (256 KB).
send_buffer_sizeinteger262144TCP send buffer size in bytes (256 KB).
crypto_worker_countinteger4Threads dedicated to encryption/decryption. Higher values improve throughput under heavy concurrent load.
[performance]
worker_threads = 4
crypto_worker_count = 4

server_address = "wss://your.server.com/api/v1/ws"
identity_key_file = "~/.config/rvpn/identity.key"
prekey_bundle = "~/.config/rvpn/prekey-bundle.json"
tls_fingerprint = "chrome"
[socks5]
listen_address = "127.0.0.1:1080"
[http_proxy]
enabled = true
listen_address = "127.0.0.1:8118"
[tun]
enabled = true
mtu = 1420
routes = ["0.0.0.0/0"]
[dns_proxy]
enabled = true
listen_address = "127.0.0.1:53"
nameservers = ["223.5.5.5:53", "1.1.1.1:53", "8.8.8.8:53"]
[split_tunnel]
enabled = true
builtin_bypass_countries = ["CN"]
block_ads = true
[network]
prefer_ipv4 = true
dns_cache_enabled = true
[server_identity]
trust_on_first_use = true
strict = true