Skip to content

OpenWrt

The rVPN OpenWrt package puts the daemon on your router. LAN clients pick it up either automatically (via WPAD-advertised SOCKS5 / HTTP proxy) or transparently (in TUN mode, with policy routing sending forwarded LAN traffic through the tunnel).

Ships as two .ipk packages:

  • rvpn-client — the daemon, procd service, UCI schema, hotplug policy routing. Arch-specific.
  • luci-app-rvpn — the LuCI 23.05 web UI. Arch-independent.
  • OpenWrt 22.03 or later.
  • Router with enough RAM and flash for a ~5–10 MB static binary. Typical modern devices are fine; older 8 MB flash routers may struggle.
  • A deployed rVPN server (address + prekey bundle).

Grab the two .ipk files for your router’s architecture and install with opkg:

Terminal window
opkg install rvpn-client_1.3.1_<arch>.ipk
opkg install luci-app-rvpn_1.3.1_all.ipk

Supported architectures: x86_64, aarch64, armv7, mipsel_24kc, mips_24kc.

The postinst hook auto-generates an identity key at /etc/rvpn/identity.key and enables the service. The daemon stays stopped until you configure a server address.

Open the router’s admin UI and navigate to Services → VPN → rVPN:

  1. Server — paste the base URL (e.g. wss://vpn.example.com). The correct WebSocket path is appended automatically.
  2. Mode — pick SOCKS5 Proxy for opt-in per-app routing on LAN clients (paired with WPAD auto-discovery), or TUN (Full VPN) for transparent whole-LAN routing.
  3. Prekey Bundle — paste the JSON your server operator provided into the Prekey Bundle text area and hit Save & Apply.
  4. Server Fingerprint (optional) — paste the operator’s ik:1:… pin here for strict pinning. Leave blank to Trust On First Use.
  5. Enabled — flip on. Hit Save & Apply.

The status pill on the Overview section shows Connected / Connecting / Disabled based on the live procd instance.

The UCI schema is straightforward:

Terminal window
uci set rvpn.main.server_address='wss://your-server.com'
uci set rvpn.main.mode='socks5'
uci set rvpn.main.enabled='1'
# Optional: strict pin instead of TOFU
uci set rvpn.server_identity.server_fingerprint='ik:1:...'
uci set rvpn.server_identity.strict_mode='1'
uci commit rvpn
/etc/init.d/rvpn restart

Every UCI option is documented inline in /etc/config/rvpn on the router. The most useful ones:

SectionOptionPurpose
mainserver_addressBase URL of the rVPN server (no path).
mainmodesocks5 or tun.
server_identityserver_fingerprintCanonical ik:1: pin. Blank = TOFU.
server_identitytrust_on_first_use1 (default) captures the identity on first connect.
server_identitystrict_mode1 refuses unknown identities even on first connect (needs the pin set).
socks5listen_addressWhere the SOCKS5 proxy binds. Default 0.0.0.0:1080.
http_proxyenabledAlso expose an HTTP proxy. Off by default.
tunip_addressLocal TUN address. Default 10.200.0.2/24.
split_tunnelbypass_countriesComma-separated ISO codes whose CIDR ranges skip the tunnel.
networkdns_serversFallback DNS resolvers.
wpadenabledAdvertise the SOCKS5 proxy via DHCP option 252. On by default.

When rVPN starts in SOCKS5 mode, the init script generates /www/wpad.dat at runtime using the router’s live LAN IP (uci get network.lan.ipaddr). It’s advertised to LAN clients via DHCP option 252. Clients that honour WPAD — macOS, Chrome, Firefox with the right prefs — pick the proxy up automatically.

If a device doesn’t honour WPAD, point it at SOCKS5 <router-lan-ip>:1080 manually.

In TUN mode the daemon creates a virtual interface (default rvpn0) and the hotplug script /etc/hotplug.d/iface/99-rvpn-tun sets up policy routing on both IPv4 and IPv6 as soon as the interface is up:

  • Table 100 gets a default route via the VPN gateway.
  • Rules match iif br-lan at priority 100 — LAN clients hit the table, the router’s own outbound traffic does not.

The rvpn firewall zone masquerades on egress and rejects inbound on both address families. So dual-stack LANs don’t leak IPv6 straight to WAN.

Same model as every other rVPN client: on first successful connect the daemon captures the server’s Ed25519 identity in the canonical ik:1:<base32> form. If the server ever presents a different identity without a signed rotation, the daemon refuses to connect.

To pin a specific identity from the start, paste the operator’s ik:1: pin into Server Fingerprint (LuCI) or set rvpn.server_identity.server_fingerprint (CLI). Setting strict_mode='1' refuses unknown identities even on the very first connect — pair it with a pin.

See Server Identity Pinning for the full model, including how operators rotate the identity key.

The tunnel is up but LAN clients don’t route through it (TUN mode)

Section titled “The tunnel is up but LAN clients don’t route through it (TUN mode)”

Check the policy routing rules and default route are actually in place after the interface comes up:

Terminal window
ip rule show | grep br-lan
ip route show table 100

Both should show entries. If they’re missing, logread -e rvpn will tell you why the hotplug script bailed (no gateway resolved, br-lan not found, etc.).

LuCI shows “Disabled” but the daemon is running

Section titled “LuCI shows “Disabled” but the daemon is running”

Save & Apply didn’t reload the daemon. /etc/init.d/rvpn reload should re-run generate_config; if not, the reload trigger might not be firing:

Terminal window
uci show rvpn
/etc/init.d/rvpn restart

Confirm the DHCP option landed:

Terminal window
uci get dhcp.@dnsmasq[0].dhcp_option

Expect 252,http://<router-lan-ip>/wpad.dat in the list. If not, the WPAD render failed — check logread -e rvpn for the LAN IP resolution warning.

”profile is missing a prekey bundle” at start

Section titled “”profile is missing a prekey bundle” at start”

The daemon refuses to start without a prekey bundle at /etc/rvpn/prekey-bundle.json. Paste the operator’s JSON into the LuCI Prekey Bundle text area, or drop the file in directly via SCP.

For more troubleshooting help, see the Troubleshooting Guide.