Build a Road-Warrior VPN with OpenFactory

WireGuard and IKEv2/X.509 remote access

Updated July 21, 2026

← Back to Blog

A road-warrior VPN gives a laptop or phone an authenticated route back to a fixed network. The gateway is the only internet-facing service; the NAS, camera network, development hosts, and internal dashboards remain private.

Road-warrior VPN trust and routing pathSeparate laptop and phone identities connect to one public gateway. Split-tunnel policy sends only the protected home subnet through the encrypted tunnel.Laptop identity10.252.x.x / certificatePhone identityDistinct key or certificateUDP tunnelUDP tunnelVPN gatewayPublic endpointForward only allowed routes10.44.0.0/24Protected LANHome computer + servicesNo public exposureSeparate credentialsSplit tunnel: ordinary internet traffic stays on each client's local connection
The route policy and the identity policy are separate decisions. A client can be authenticated and still receive access only to the exact private subnet it needs.

Before you build

  • A public IPv4 address or DNS name that reaches the gateway.
  • A router or cloud firewall rule for the selected UDP ports.
  • A protected subnet that does not overlap the networks clients commonly use.
  • A recovery path to the gateway before changing routing or firewall policy.

The prompts below use RFC 1918 lab addresses so OpenFactory can build and test them safely. Before installing the bundle on real hardware, replace the lab WAN address with your reachable IP or DNS name and confirm the interface order.

Option 1: WireGuard split tunnel

This is the smaller operational surface. Each client receives a distinct key and routes only the home subnet through the tunnel. General browsing continues to use the client's local connection.

Build and validate a road-warrior WireGuard deployment named `home-remote-access` as a BUILD_PLAN.

Create a `device_kind=linux-build` gateway named `home-gateway` on Debian Trixie with the `headless`, `ssh`, and `vpn-wireguard` features. Give it two static interfaces in this order: `172.31.210.10/24` on a `wan` network whose gateway is `172.31.210.1` and is the default route, then `10.44.0.1/24` on a `home-lan` network. Include tcpdump, iproute2, curl, and nftables for operations. Do not add a desktop or embed private keys in the recipe.

Also create a `device_kind=linux-build` computer named `home-computer` on Debian Trixie with the `headless` and `ssh` features, plus iproute2, iputils-ping, and curl. Connect its only static interface, `10.44.0.10/24`, to `home-lan`. Add an `os.startup_scripts` oneshot named `vpn-return-route`, after `network-online.target`, that runs `ip route replace 10.252.10.0/24 via 10.44.0.1`. This computer represents a real host on the protected LAN and must be a separate recipe and topology node.

Set `plan.vpn` to protocol `wireguard`, implementation `linux`, mode `roadwarrior`, authentication `public-key`, tunnel CIDR `10.252.10.0/24`, listen port `51820`, and DNS `1.1.1.1`. The endpoint is `home-gateway`, its public endpoint is `172.31.210.10`, and its protected subnet is `10.44.0.0/24`. Generate split-tunnel client profiles named `laptop` and `phone`, each with `allowed_subnets=["10.44.0.0/24"]` and `full_tunnel=false`.

Add `command_output` group assertions expecting `ready` for all of these checks: on `home-gateway`, run `wg show wg0 | grep -q 'listening port: 51820' && ping -c 3 -W 3 10.44.0.10 >/dev/null && echo ready`; on `home-computer`, run `ip route get 10.252.10.2 | grep -q 'via 10.44.0.1' && echo ready`. Keep all credentials in the owner-only deployment bundle generated by OpenFactory.

Option 2: strongSwan IKEv2 with X.509

Choose this when IPsec interoperability or certificate identities are a requirement. OpenFactory creates a private CA, an endpoint certificate, and one certificate per client. Each client directory also includes a password-protected PKCS#12 profile and the gateway, identity, route, and import details needed by native IKEv2 clients. Verify the enrollment workflow on every target platform.

Build and validate a road-warrior IKEv2 deployment named `home-ikev2-access` as a BUILD_PLAN.

Create a `device_kind=linux-build` gateway named `ikev2-gateway` on Debian Trixie with the `headless`, `ssh`, and `vpn-strongswan` features. Give it two static interfaces in this order: `172.31.211.10/24` on a `wan` network whose gateway is `172.31.211.1` and is the default route, then `10.45.0.1/24` on a `home-lan` network. Include tcpdump, iproute2, curl, and nftables. Do not create XFRM interfaces, pre-shared keys, or certificates in the recipe.

Also create a `device_kind=linux-build` computer named `home-computer` on Debian Trixie with the `headless` and `ssh` features, plus iproute2, iputils-ping, and curl. Connect its only static interface, `10.45.0.10/24`, to `home-lan`. Add an `os.startup_scripts` oneshot named `vpn-return-route`, after `network-online.target`, that runs `ip route replace 10.252.11.0/24 via 10.45.0.1`. This computer represents a real host on the protected LAN and must be a separate recipe and topology node.

Set `plan.vpn` to protocol `ikev2`, implementation `linux`, mode `roadwarrior`, authentication `x509`, tunnel CIDR `10.252.11.0/24`, listen port `500`, and DNS `1.1.1.1`. The endpoint is `ikev2-gateway`, its public endpoint is `172.31.211.10`, and its protected subnet is `10.45.0.0/24`. Generate split-tunnel X.509 client profiles named `laptop` and `phone`, each with `allowed_subnets=["10.45.0.0/24"]` and `full_tunnel=false`.

Add `command_output` group assertions expecting `ready` for all of these checks: on `ikev2-gateway`, run `swanctl --list-conns | grep -q 'home-ikev2-access' && ping -c 3 -W 3 10.45.0.10 >/dev/null && echo ready`; on `home-computer`, run `ip route get 10.252.11.2 | grep -q 'via 10.45.0.1' && echo ready`. Keep the CA, endpoint certificate, client certificates, and private keys in the owner-only deployment bundle generated by OpenFactory.

How the two options differ operationally

WireGuard's AllowedIPs binds a peer identity to routes and accepted source addresses. The WireGuard protocol overview calls this cryptokey routing. Removing one peer entry revokes that device without changing the others.

The IKEv2 option loads a CA, one gateway certificate, and individual client certificates into swanctl. The strongSwan configuration reference documents the connection, identity, certificate, and address-pool fields used here. Revocation needs an explicit CA process; deleting a profile file alone is not revocation.

What Deploy does

  1. Opens Elster Terminal with the registered prompt id, not editable prompt text in the URL.
  2. Submits the exact allowlisted prompt and creates the build plan preview.
  3. Starts the build once for that launch id, even if the browser retries the request.
  4. Boots the gateway and a computer on its protected LAN, applies the generated endpoint files, and verifies LAN reachability and the return route.
  5. Exposes the private deployment ZIP only to the build-group owner.
Treat the ZIP as a secret. It contains unencrypted private keys. Keep the CA key offline after enrollment, distribute only each client's own directory, and rotate credentials if the archive leaves the intended owner's control.

Production checklist

  • Use a stable endpoint and forward WireGuard UDP 51820 or IKEv2 UDP 500 and 4500.
  • Keep split-tunnel routes narrow unless a full-tunnel policy is intentional.
  • Restrict forwarding from the VPN pool to the minimum required LAN ranges.
  • Back up the CA separately from the gateway and define a revocation process.
  • Test from an external network, then verify DNS, routing, and reconnect behavior after roaming.

To connect two complete networks instead of individual clients, use the companion WireGuard site-to-site guide or the Vyatta IKEv2 guide.

Ready to ship this in production?

OpenFactory's free flow is for browsing. Persistent VMs, SSH access, snapshots, your own ISO, and fleet deployment live on a paid plan.