Skip to content

Config URIs & QR codes ​

A client config can be exported as a single shadowvpn:// URI (the config JSON, URL-safe Base64) and imported back — handy for moving a config to another device by copy-paste or by scanning a QR code.

This lives in a separate shadowvpn-uri binary so the server/client builds stay lean; build it with the uri feature (off by default):

sh
cargo build --release --features uri --bin shadowvpn-uri

Usage ​

sh
# Print the shadowvpn:// URI for a config…
shadowvpn-uri export -c client.json

# …or also render a scannable QR code to the terminal:
shadowvpn-uri export -c client.json --qr

# Import a URI back into a JSON config (omit -o to print to stdout):
shadowvpn-uri import 'shadowvpn://…' -o client.json

# Import by decoding a QR-code image instead of pasting the URI:
shadowvpn-uri import --image config-qr.png -o client.json

# Render an existing shadowvpn:// URI as a terminal QR code (also reads stdin):
shadowvpn-uri qr 'shadowvpn://…'

Caveats ​

  • The URI carries every config field — including the password. Treat a shadowvpn:// URI (or its QR code) as a secret.
  • File-path fields (gfwlist, chnroute, geoip, cache_file) are only meaningful on the host that has those files — re-point them after importing.
  • When several clients share one server, omit tun_ip and peer_ip. Magic DNS hostname is not in the URI (same as node_id). so one URI/QR works on every device and each still gets a unique tunnel IP. The persisted node_id lives in <config>.state next to the imported JSON — it is not in the URI. Alternatively give each client a distinct static tun_ip, or run the server with --nat (no client↔client) so every device can share one identical placeholder config.

The desktop app supports shadowvpn:// URI import/export in its profile manager, so a QR/URI produced here drops straight into the GUI.

Released under the MIT License.