Skip to content

Configuration reference ​

Configuration can come from a JSON config file, CLI flags, or both. CLI flags take precedence over JSON file values. Defaults are applied for anything not supplied. Both binaries accept -c, --config <PATH>.

Common fields (server + client) ​

JSON fieldCLI flagMeaningRequiredDefault
server-l, --listen (server) / -s, --server (client)server: UDP bind address; client: remote host:portyes—
password-k, --passwordpre-shared password; master key derived from ityes—
cipher-m, --cipheraes-128-gcm | aes-256-gcm | chacha20-poly1305nochacha20-poly1305
tun_name--tun-nameexplicit TUN interface name (e.g. utun7, tun0)noOS picks
tun_ip--tun-iplocal IPv4 address on the TUN interfaceserver: yes; client: both-or-neither with peer_ip—
tun_netmask--tun-netmaskIPv4 netmask for the TUN interfaceno255.255.255.0
peer_ip--peer-ippoint-to-point peer IPv4 (server: reserved static client IP; client: server IP)server: yes; client: both-or-neither with tun_ip—
mtu--mtuTUN interface MTUno1400
tun_ip6--tun-ip6optional IPv6 address + prefix on the TUN, CIDR form (e.g. fd07:7::2/64) — used by mesh routingnonone
obfs(config only)carrier obfuscation: none | quic | base64 — both ends must matchnonone

The alias chacha20-ietf-poly1305 is accepted for cipher and treated as chacha20-poly1305.

Server-only fields ​

JSON fieldCLI flagMeaningDefault
nat--nattell clients apart by UDP endpoint and NAT them onto internal IPs, so all clients can share one config (NAT mode). Exclusive with assignment and mesh.false
lease_ttl_secs--lease-ttl-secsNAT mode: reclaim a client's internal-IP lease after this many idle seconds; also the expiry for advertised mesh routes whose owner went quiet, and for learned inner-IP → UDP mappings120
approve_routes--approve-routesallowlist of CIDRs: an advertised route is approved when it equals, or is a subnet of, an entry (mesh routing)none
auto_approve_routes--auto-approve-routesapprove every advertised routefalse
assign_pool--assign-poolIPv4 CIDR the assigner may hand out (subset of the TUN network). Allocator-only; the Assign reply still carries the TUN netmask (auto-assign)TUN host range
reserved_ips--reserved-ipsextra IPv4s never auto-assigned (unioned with peer_ip, which is always reserved — typically .2)[peer_ip]
assign_ttl_secs--assign-ttl-secsidle time before an assignment lease is reclaimed604800 (7d)
lease_file--lease-fileassignment lease persist path. "-" disables. Default: <config>.leases.json next to --config, else /var/lib/shadowvpn/leases.json (%PROGRAMDATA%\shadowvpn\leases.json on Windows)see left
hostname--hostnameMagic DNS name published as this server's tunnel IP (Magic DNS)sanitized OS hostname

Mesh routing (approve_routes / auto_approve_routes / tun_ip6) and automatic assignment require the default learning mode and cannot be combined with nat. On the client, omit both tun_ip and peer_ip to request an assignment; setting only one is an error.

Client-only fields ​

Tunnel behaviour ​

JSON fieldCLI flagMeaningDefault
keepalive_secs--keepalive-secskeepalive interval in seconds — keep it below the path's UDP NAT timeout. Auto-assign clients send AssignRequest on this tick.15
state_file--state-filepersisted node_id + last assignment (auto-assign). Default: <config>.state next to -c, else a hash of the server string under the platform state dir. Not carried in a URI/QR.see left
advertise_routes--advertise-routesIPv4/IPv6 subnets behind this client to advertise to the server (comma-separated CIDRs on the CLI, array in JSON)none
accept_routes--accept-routesinstall subnet routes pushed by the server onto the TUN; removed on withdrawal and exitfalse
hostname--hostnameMagic DNS name announced to the server. Not carried in a URI/QR.sanitized OS hostname
magic_dns--magic-dns / --no-magic-dnsresolve joined peers by hostname (Magic DNS)true
magic_dns_suffix--magic-dns-suffixsuffix for Magic DNS names (laptop and laptop.<suffix>)svpn

Policy routing ​

JSON fieldCLI flagMeaningDefault
mode--modefull | gfwlist | chinadnsfull
dns_listen--dns-listenaddress the split-DNS proxy listens on127.0.0.1:53
dns_local--dns-localdomestic / direct DNS upstream114.114.114.114:53
dns_remote--dns-remoteclean DNS upstream (reached through the tunnel)8.8.8.8:53
gfwlist--gfwlistdomain-suffix file (gfwlist mode; optional force-tunnel list in chinadns mode)auto-discovers a bundled gfwlist.txt
chnroute--chnrouteChina CIDR file (chinadns mode)—
geoip--geoipGeoLite2/GeoIP2 .mmdb; builds the China set from it (takes precedence over chnroute)auto-discovers a bundled GeoLite2-Country.mmdb
geoip_country--geoip-countryISO country code to select from the GeoIP databaseCN
prewarm--no-prewarm (disable)list of domains to pre-resolve into the cache on startupbuilt-in list
cache_file--cache-file / --no-cache-persistpersist the DNS cache across restartsdns-cache.json (next to the binary)
dns_timeout_ms(config only)upstream DNS query timeout in milliseconds3000

Maintenance flags ​

CLI flagMeaning
--restore-dnsrestore the system resolver from the journal left by a run that did not exit cleanly, or reset a leftover 127.0.0.1 to automatic/DHCP DNS, then exit (no tunnel is brought up). Used by the desktop app on launch to heal DNS after a crashed client.

Full examples ​

Annotated server and client examples, including NAT mode and policy routing, live in the guides:

Released under the MIT License.