OPNsenseXXI · WireGuardWireGuard
WireGuard remote access — VPN for individual users, full-tunnel and split-tunnel
What you'll learn
- Plan addressing for a WireGuard remote-access deployment with many users
- Configure the firewall, generate per-user keys and configuration profiles, distribute to clients
- Choose between full-tunnel and split-tunnel routing and apply the right configuration
- Write firewall rules and outbound NAT that scale with the user count
- Manage peer lifecycle — onboarding, offboarding, key rotation
Prerequisites
Verified against OPNsense 25.x · FreeBSD 14.x · PF (FreeBSD packet filter) FreeBSD 14.x · Unbound 1.20+ · Kea DHCP OPNsense 25.x plugin · WireGuard in-kernel + OPNsense plugin · strongSwan (IPsec plugin) OPNsense 25.x plugin · OpenVPN 2.6.x · Suricata 7.x · 2026-08-14
A remote-access deployment is where WireGuard’s simplicity pays off the most. A site-to-site tunnel has two peers and one configuration; a remote-access deployment may have hundreds of peers, each with their own key, their own tunnel IP, and their own access policy. Without discipline — addressing scheme, per-peer key distribution, peer lifecycle — the deployment grows into an unmaintainable mess. With discipline, it scales linearly with the operator’s patience.
This lesson covers the addressing plan, the per-peer configuration generation, the choice between full-tunnel and split-tunnel routing, the firewall rules and outbound NAT that scale, and the operational discipline for managing peer lifecycle.
The addressing plan
A remote-access deployment with N users needs:
- A VPN pool — the range of addresses assigned to remote users. Typically a
/24(254 addresses) for small deployments, a/20or/16(4,094 or 65,534 addresses) for large deployments. - A unique
/32for each user — every peer gets exactly one address from the pool. - A corporate subnet — the inside network users reach when connected. The pool must not overlap with the corporate subnet or with any site-to-site tunnel subnets.
Example plan for a 200-user deployment:
| Subnet | Purpose |
|---|---|
10.0.0.0/16 | Corporate LAN |
10.99.0.0/24 | Remote-access VPN pool |
10.99.1.0/24 | Reserved for growth or second VPN pool |
Each user gets a /32 from 10.99.0.0/24. User 1 is 10.99.0.1/32; user 200 is 10.99.0.200/32. The pool grows linearly until 10.99.0.254/32 (the broadcast address is unusable); the deployment is at capacity at ~250 users with this pool.
Configuring the firewall
The firewall-side configuration is one WireGuard instance and many peer entries:
WireGuard instance:
- Listen port: 51820.
- Tunnel address: the firewall’s /32 within the pool (e.g.
10.99.0.1/32— the firewall itself is at the gateway address of the pool).
Peer entries (one per user):
| Field | Value |
|---|---|
| Public key | The user’s WireGuard public key |
| AllowedIPs | The user’s unique /32 (e.g. 10.99.0.5/32) |
| Endpoint | Optional — only if the user has a stable public IP (rare for road warriors) |
| Persistent keepalive | 25 (recommended for users behind NAT) |
The firewall holds the public key of every user; each user holds the firewall’s public key plus their own private key. The handshake authenticates both sides.
$ wg show wg0 | head -30interface: wg0
public key: serverpubkey...=
private key: (hidden)
listening port: 51820
peer: user1publickey...=
allowed ips: 10.99.0.5/32
latest handshake: 1 minute ago
transfer: 156.4 MiB received, 78.2 MiB sent
peer: user2publickey...=
allowed ips: 10.99.0.6/32
latest handshake: 12 seconds ago
transfer: 2.3 GiB received, 1.1 GiB sent
peer: user3publickey...=
allowed ips: 10.99.0.7/32
latest handshake: 3 hours ago
transfer: 89.1 MiB received, 45.6 MiB sentIllustrative output
Generating the client configuration
For each user, the operator generates a WireGuard configuration profile. The profile is a text file the user imports into the WireGuard client.
The client configuration includes:
- Interface section: the user’s private key, the tunnel address (
10.99.0.5/32), the DNS server (typically the firewall’s internal DNS, e.g.10.0.0.1). - Peer section: the firewall’s public key, the AllowedIPs (which traffic routes through the tunnel), the endpoint (the firewall’s public IP and port).
For split-tunnel (corporate traffic only):
[Interface]
PrivateKey = user1privatekeyhere==
Address = 10.99.0.5/32
DNS = 10.0.0.1
[Peer]
PublicKey = serverpubkeyhere==
Endpoint = vpn.example.com:51820
AllowedIPs = 10.0.0.0/16, 172.16.0.0/12
PersistentKeepalive = 25
For full-tunnel (all traffic):
[Interface]
PrivateKey = user1privatekeyhere==
Address = 10.99.0.5/32
DNS = 10.0.0.1
[Peer]
PublicKey = serverpubkeyhere==
Endpoint = vpn.example.com:51820
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25
The difference: AllowedIPs = 0.0.0.0/0, ::/0 for full-tunnel routes every IPv4 and IPv6 packet through the tunnel; AllowedIPs = 10.0.0.0/16, 172.16.0.0/12 for split-tunnel routes only the corporate subnets.
$ qrencode -t ansiutf8 < user1.conf[QR code rendered as ANSI art]
The QR code encodes the WireGuard client configuration
(interface + peer sections). Scanning with a mobile
WireGuard app imports the configuration in one step.
The QR code is the distribution channel for users who
do not have file-based configuration delivery (a
quick way to onboard a phone or a field laptop).Illustrative output
Firewall rules and NAT for remote access
For split-tunnel, the rules are simple — the VPN pool can reach corporate subnets:
# On the WireGuard interface: allow VPN users to reach corporate subnets
pass in on wg0 inet from 10.99.0.0/24 to 10.0.0.0/16 keep state
# On the LAN interface: allow corporate hosts to reach VPN users
pass in on lan inet from 10.0.0.0/16 to 10.99.0.0/24 keep state
For full-tunnel, the rules add Internet access — every VPN user’s traffic flows through the firewall to the Internet:
# On the WireGuard interface: allow VPN users to reach any internal subnet
pass in on wg0 inet from 10.99.0.0/24 to 10.0.0.0/8 keep state
# Outbound NAT for VPN traffic on the WAN
nat on igb1 inet from 10.99.0.0/24 to any -> (igb1)
The outbound NAT rule translates the VPN user’s source IP (10.99.0.5) to the firewall’s WAN IP when traffic goes to the Internet. Without it, the user can reach internal subnets but not the Internet.
For per-user authorisation (e.g. admins can reach more subnets than regular users), use aliases to slice the pool:
VPNAdmins = 10.99.0.0/26 # admins (addresses 1-62)
VPNUsers = 10.99.0.64/26 # regular users (addresses 65-126)
pass in on wg0 inet from VPNAdmins to 10.0.0.0/8 keep state # admins reach everything
pass in on wg0 inet from VPNUsers to 10.0.10.0/24 keep state # users reach one subnet only
The discipline: slice the pool by user role, write rules per slice, and assign /32 addresses within the appropriate slice.
Peer lifecycle
Three lifecycle events matter:
Onboarding. Generate a key pair on the client’s device (or pre-generate and deliver securely). Add the peer’s public key to the firewall with the assigned /32 AllowedIPs. Generate the client configuration profile (with the firewall’s public key and the user’s private key). Distribute the profile securely. The user imports and connects.
Offboarding. Remove the peer entry from the firewall. The user’s private key no longer matches any peer; the user’s connections are terminated; the user cannot reconnect. The discipline: remove the peer entry promptly when an employee leaves — a peer entry that survives the user is a security liability.
Key rotation. Generate a new key pair for the user; update the peer entry on the firewall with the new public key; distribute a new client configuration with the new private key. The rotation cadence depends on the threat model: annual rotation is a common baseline; rotation on any suspected compromise is mandatory.
Summary
- A remote-access deployment has one WireGuard instance and many peer entries, each with a unique /32 AllowedIPs.
- Client configurations are generated per user, containing the user’s private key and the firewall’s public key. Distribution is over an authenticated channel.
- Split-tunnel routes corporate traffic only; full-tunnel routes everything. Full-tunnel requires outbound NAT on the WAN interface for Internet access.
- Aliases (e.g.
VPNAdmins,VPNUsers) slice the pool by role and scale the rule set. - Peer lifecycle (onboarding, offboarding, key rotation) is operational discipline: peer entries must be removed when employees leave, and rotated on suspected compromise.
Knowledge check · 4 questions
Q1. A 200-user remote-access VPN deployment assigns every peer AllowedIPs of 10.99.0.0/24. What is the most likely consequence?
Q2. A full-tunnel WireGuard remote-access VPN (peers with AllowedIPs = 0.0.0.0/0) requires an outbound NAT rule on the WAN interface for the VPN pool; without it, clients can reach internal subnets but not the Internet.
Q3. Which of the following are valid peer lifecycle operations for a WireGuard remote-access deployment? Select all that apply.
Q4. A remote-access user connects successfully and can reach internal subnets but cannot reach external websites. The AllowedIPs is 0.0.0.0/0 (full-tunnel). What is the most likely cause?
Passing score: 75%. Answers are checked in this browser.