If you’re running services at home and hiding them behind a VPS, or you want your entire LAN to egress through a remote server, configuring a WireGuard client on OPNsense is one of the cleanest ways to do it.
But here’s the part most guides skip: getting the tunnel up is easy. Getting LAN routing, firewall rules, static routes, and return-path routing correct is where things break.
Ask me how I know.
Traffic left on the WireGuard interface fine. Return packets came back on WAN and got dropped. I had to understand asymmetric routing and add policy-based routing to fix it. The good news? Once you know where to look, OPNsense makes this straightforward.
In this guide, you’ll configure OPNsense as a WireGuard client for a VPS tunnel, route LAN traffic through it, and avoid the common asymmetric routing traps. I also include pfSense WireGuard equivalents with enough detail to follow along on either platform.
Why Run a VPS WireGuard Tunnel From Your Router?
Common use cases:
- Expose home services safely via a VPS reverse proxy
- Bypass CGNAT
- Force LAN traffic out through a VPS IP
- Site-to-site networking
- WireGuard port forwarding setups
- Segmented VLAN traffic through different egress paths
Instead of configuring WireGuard on individual devices, configure it once on your router. Every LAN device can then use the VPS tunnel without touching its own network config.
This is where OPNsense shines.
Prerequisites
Before touching OPNsense:
- VPS running WireGuard server
- VPS public IP and port, default
51820/UDP - VPS public key
- Client tunnel IP, example
10.10.10.2/24 - Server tunnel IP, example
10.10.10.1 - Server configured to allow this client with
AllowedIPsset appropriately. For a full tunnel, that’s usually0.0.0.0/0on the client peer entry.
Recommended:
- OPNsense 24.x or newer
- Config backup before changes
If your VPS setup differs, follow the VPS provider’s docs first.
Step 1: Install and Enable WireGuard on OPNsense
WireGuard is a plugin in OPNsense.
- Go to System > Firmware > Plugins
- Install
os-wireguard - Go to VPN > WireGuard > General
- Enable WireGuard
OPNsense uses an Instances and Peers model. It’s cleaner than pfSense’s layout, which we’ll get to later.
Step 2: Create the WireGuard Client Instance
Go to:
VPN > WireGuard > Instances > Add
Configure:
- Enabled: Yes
- Name:
VPS_Tunnel - Tunnel Address:
10.10.10.2/24 - MTU:
1420- If using PPPoE or VLAN tagging on WAN, start with
1412. More on MTU below.
- If using PPPoE or VLAN tagging on WAN, start with
- Disable Routes: Unchecked
Now add a Peer under this instance:
- Public Key: VPS public key
- Endpoint Address:
VPS_PUBLIC_IP:51820 - Allowed IPs:
0.0.0.0/0for full tunnel- Or specific VPS subnets for split tunnel
- Persistent Keepalive:
25seconds. Important if OPNsense is behind NAT.
Save and Apply.
Verify the Handshake
Go to:
VPN > WireGuard > Status
You should see:
- A recent handshake timestamp
- RX/TX counters increasing
If not:
- Check outbound UDP 51820 is allowed on your WAN
- Verify VPS firewall rules
- Confirm keys match
- Run
wg showfrom the OPNsense shell
Handshake failures are almost always:
- Port blocked (check both sides)
- Key mismatch
- Wrong endpoint IP or port
Step 3: Assign the WireGuard Interface
This is where many people stop too early. And it’s where things start breaking.
Go to:
Interfaces > Assignments
Add the new interface, typically wg0.
Then:
- Enable it
- Rename to
WG_VPS - IPv4 Configuration: Static
- Set address to
10.10.10.2/24
Save and apply.
Do You Need to Assign It?
If you only want the firewall itself to use the tunnel, technically no.
If you want any of the following, you must assign it:
- LAN routing through the tunnel
- Policy-based routing
- Gateway control
- VLAN routing
- Internet over the tunnel
No assignment means no gateway. No gateway means no policy routing. No policy routing means LAN traffic goes out your WAN and you wonder why nothing works.
Step 4: Firewall Rules for the pfSense WireGuard Client
Now we make traffic flow. You need rules in two places.
WAN Rule (Usually Not Needed)
Most default OPNsense setups allow all outbound traffic. If yours restricts outbound, you need to allow the WireGuard handshake:
Firewall > Rules > WAN
- Action: Pass
- Direction: Out (this is an outbound rule, not inbound)
- Protocol: UDP
- Destination Port: 51820
If your WAN already has a permissive outbound rule, skip this. Don’t poke holes you don’t need.
WireGuard Interface Rule
Go to:
Firewall > Rules > WG_VPS
Add:
- Action: Pass
- Source:
WG_VPS net - Destination:
LAN netorany
For multi-peer or multi-subnet setups, create explicit aliases instead of relying on auto-generated “WireGuard net” entries. Those can behave unexpectedly when you add more peers later.
Step 5: Gateway and Static Routes
Go to:
System > Gateways > Configuration
Ensure a gateway exists for WG_VPS.
If not, add:
- Interface: WG_VPS
- Gateway IP:
10.10.10.1 - Name:
WG_VPS_GW
Now static routes:
System > Routes > Configuration
Add routes for:
- VPS internal subnets
- Remote private networks reachable over the tunnel
Example:
- Network:
172.16.0.0/24 - Gateway:
WG_VPS_GW
If you used 0.0.0.0/0 in AllowedIPs and want a full tunnel for selected devices, use policy routing instead. Do not change the system default gateway unless you intend to send all firewall traffic through the VPS. That includes DNS, package updates, and everything else.
Step 6: LAN Routing Through the VPS Tunnel
This is where it actually works.
Go to:
Firewall > Rules > LAN
Add a rule:
- Action: Pass
- Source:
LAN net(or an alias for specific hosts/subnets) - Destination:
anyor specific subnet - Advanced > Gateway:
WG_VPS_GW
This is policy-based routing. Traffic matching this rule exits through the WireGuard tunnel instead of WAN.
Place this rule above the default “allow LAN to any” rule. Rule order matters in OPNsense. First match wins.
The Asymmetric Routing Problem (And How to Fix It)
Here’s what broke me.
Traffic left LAN through WG_VPS. Replies returned via the WAN default gateway. The firewall dropped them because the state table didn’t match.
That’s asymmetric routing. It’s the number one reason people think their tunnel is broken when it’s actually working.
Why It Happens
OPNsense sends traffic out WireGuard because of your policy routing rule. But return traffic from the internet may:
- Follow the system default route back out WAN
- Miss the expected connection state
- Bypass the tunnel entirely
The firewall sees a reply arriving on a different interface than the outbound packet left on. State mismatch. Drop.
Fix 1: Outbound NAT on WireGuard Interface (Most Common)
Go to:
Firewall > NAT > Outbound
Switch to Hybrid Mode.
Add a rule:
- Interface:
WG_VPS - Source:
LAN net - Translation: Interface address
This source NATs LAN traffic to the tunnel IP (10.10.10.2). Replies come back through the tunnel because the VPS sees the tunnel IP as the source.
This is the most reliable fix for full-tunnel setups.
The tradeoff: you’re hiding original LAN IPs from the VPS side. The VPS only sees 10.10.10.2 for every client. That means VPS-side logging, ACLs, and per-device access controls won’t see individual LAN addresses. For most homelab full-tunnel scenarios, that’s fine. For site-to-site setups where you need source IP visibility, see Fix 2.
Fix 2: Routed Tunnel Without NAT
If you need the VPS to see original LAN IPs (site-to-site, per-device ACLs, granular logging):
- On the VPS, add a static route for your LAN subnet (
192.168.1.0/24) pointing to the tunnel IP (10.10.10.2) - On OPNsense, make sure the WireGuard peer’s AllowedIPs includes the VPS subnet
- Skip the outbound NAT rule on
WG_VPS
The VPS now routes replies back through the tunnel because it knows your LAN subnet lives behind 10.10.10.2.
This is cleaner architecturally but requires you to control routing on the VPS side. If your VPS is a cloud instance with limited routing options, NAT is simpler.
Fix 3: Policy-Based Routing on Every Interface
If you use VLANs:
- Add a policy route rule on each VLAN interface
- Set gateway to
WG_VPS_GW
Miss one VLAN and that traffic leaks out WAN. Every interface that should use the tunnel needs its own rule.
A Note on Reply-To
OPNsense and pfSense both use reply-to directives on interface rules. This tells the firewall to send reply traffic back out the interface it arrived on, which normally prevents asymmetric routing for WAN traffic.
But reply-to can interfere with policy-based routing on internal interfaces. If you see traffic ignoring your policy route, check whether a reply-to on the WG_VPS interface rule is overriding your intended path. You can disable reply-to on specific rules under Advanced Options in the rule editor.
VLAN Considerations
If your LAN is segmented:
- Apply policy routing per VLAN interface
- Add firewall rules on each VLAN
- Add static routes if required
MTU becomes more sensitive with VLANs.
If you use PPPoE or VLAN tagging on WAN, set WireGuard MTU to 1412 and test. The reason: WireGuard adds 60 bytes of overhead. Standard Ethernet MTU is 1500. PPPoE eats 8 bytes. VLAN tagging eats 4. So 1500 - 8 - 60 = 1432 for PPPoE, and lower if you also tag VLANs. Start conservative.
Test with a do-not-fragment ping:
ping -s 1392 -M do 10.10.10.1
Why 1392? Because ping adds 28 bytes of ICMP/IP header. 1392 + 28 = 1420, which matches the default WireGuard MTU. If that fragments or times out, reduce MTU further.
WireGuard Port Forwarding Through a VPS
If you use the VPS as a reverse proxy or need to expose services, here’s the packet flow:
- Internet client sends a request to VPS_PUBLIC_IP:443
- VPS receives it and forwards to
10.10.10.2:443via the WireGuard tunnel (using iptables DNAT or a reverse proxy like nginx/caddy) - OPNsense receives it on the
WG_VPSinterface - OPNsense NAT port forward sends it to the internal LAN host (e.g.,
192.168.1.50:443) - LAN host replies, traffic goes back through OPNsense, through the tunnel, back to VPS, back to the client
On OPNsense:
- Create a NAT port forward on
WG_VPS - Destination:
10.10.10.2 - Redirect target: internal LAN IP and port
Make sure the corresponding firewall rule is created (OPNsense can auto-generate it, or add it manually).
VPS side: you need either iptables DNAT rules or a reverse proxy forwarding to the tunnel IP. If the VPS doesn’t NAT or forward properly, traffic reaches the tunnel but has nowhere to go.
This enables clean WireGuard port forwarding through the VPS tunnel. It’s one of the best ways to expose services without opening ports on your home IP.
pfSense WireGuard Setup (Step-by-Step)
Now let’s talk pfSense WireGuard. The concepts are identical, but the UI and some behaviors differ.
Installation
- Go to System > Package Manager > Available Packages
- Install the WireGuard package
Unlike OPNsense, pfSense doesn’t ship WireGuard integrated. It’s package-based. Recent versions improved stability significantly, but OPNsense still feels more cohesive for WireGuard-heavy setups.
pfSense Client Configuration
Go to:
VPN > WireGuard > Tunnels > Add
- Enable: Yes
- Description:
VPS_Tunnel - Listen Port: leave blank (client mode)
- Interface Keys: generate or paste your private key
Save, then go to VPN > WireGuard > Peers > Add:
- Tunnel: select
VPS_Tunnel - Public Key: VPS public key
- Endpoint:
VPS_PUBLIC_IP:51820 - Allowed IPs:
0.0.0.0/0(full tunnel) or specific subnets - Persistent Keepalive:
25
Save.
Assign the Interface in pfSense
Interfaces > Assignments
The WireGuard tunnel appears as tun_wgX. Add it, enable it, rename to WG_VPS.
Set IPv4 to Static, address 10.10.10.2/24.
Gateway in pfSense
Go to System > Routing > Gateways. Add:
- Interface: WG_VPS
- Gateway:
10.10.10.1 - Name:
WG_VPS_GW
pfSense quirk: gateway monitoring. pfSense pings the gateway IP to check health. If your VPS doesn’t respond to ICMP on the tunnel IP, pfSense marks the gateway as down and stops routing traffic through it. Fix this by either:
- Allowing ICMP on the VPS tunnel interface
- Setting the monitor IP to something that responds (like
1.1.1.1) under Advanced gateway settings - Disabling gateway monitoring for this gateway
Firewall Rules in pfSense
Same logic as OPNsense:
- WAN: allow outbound UDP 51820 if restricted
- WireGuard interface: allow traffic from WG net
- LAN rule with Gateway set to
WG_VPS_GW(under Advanced) - Outbound NAT in Hybrid mode with a rule for
WG_VPS
The UI flow is different, but the rule structure is conceptually identical.
pfSense vs OPNsense for WireGuard
| Feature | OPNsense | pfSense |
|---|---|---|
| WireGuard integration | Plugin (feels native) | Package (add-on) |
| Config model | Instances + Peers | Tunnels + Peers tabs |
| Stability (2024+) | Strong | Much improved, still package-based |
| Gateway monitoring | Straightforward | Requires ICMP tuning for WG gateways |
| UI clarity | More intuitive | Functional but more legacy |
For WireGuard-heavy homelab setups, I’d lean OPNsense. But pfSense works. Both get the job done once configured.
Troubleshooting Guide
No Handshake
Check:
- VPS firewall allows UDP on the WireGuard port
- Endpoint IP and port are correct
- Keys match (double-check copy-paste errors)
- Run
wg showon both OPNsense and VPS
If behind NAT, ensure Persistent Keepalive is set to 25.
LAN Traffic Still Uses WAN
Common causes:
- Missing gateway in LAN rule (the Advanced > Gateway dropdown)
- Rule order wrong (policy route rule is below the default LAN allow rule)
- A floating rule is overriding your LAN rule
Fix: move the policy route rule above the default LAN allow rule. Check for floating rules under Firewall > Rules > Floating.
Traffic Leaves Tunnel but Replies Drop
Cause: asymmetric routing. The return path doesn’t match the outbound path.
Fix:
- Add outbound NAT rule on
WG_VPS(see Fix 1 above) - Verify gateway is selected in the LAN rule
- Check
reply-toisn’t interfering
“no such device wg0”
Usually means:
- Instance not enabled in WireGuard settings
- WireGuard service not started
Check: VPN > WireGuard > General and make sure the service is enabled and running.
MTU Issues
Symptoms:
- Websites partially load (small requests work, large ones stall)
- Large downloads stall or time out
- SSH works but SCP hangs
Fix:
- Reduce MTU to 1412
- Test with do-not-fragment ping (see MTU section above)
- If still broken, try 1400 or lower
Static Routes Not Working
Check:
- Gateway is assigned and active
- Interface is enabled
- “Disable Routes” is not checked in the WireGuard instance settings
OPNsense auto-adds routes based on AllowedIPs unless “Disable Routes” is checked. For complex multi-subnet environments, manage routes manually instead.
Frequently Asked Questions
How do I fix WireGuard handshake timeout on OPNsense?
Check VPS firewall, endpoint IP, and UDP 51820 access. Run wg show on both sides to confirm handshake attempts. Make sure Persistent Keepalive is set to 25 if either side is behind NAT. Key mismatch is the most common cause after port issues.
Why does LAN traffic go out WAN instead of the WireGuard tunnel?
Because the LAN firewall rule doesn’t have the gateway set to WG_VPS_GW. Open the rule, go to Advanced, and select the WireGuard gateway. Then move the rule above your default LAN allow rule. First match wins.
Do I need to assign the WireGuard interface for a basic client tunnel?
Not if you only need the firewall itself to use the tunnel. You do need it assigned if you want LAN routing, policy routing, VLAN support, or port forwarding. No assignment means no gateway, which means no policy routing options.
pfSense WireGuard client vs OPNsense: which is more stable?
As of 2024+, both work. OPNsense’s plugin is generally more consistent and better integrated into the UI. pfSense’s package has improved a lot but still feels like an add-on. For a dedicated WireGuard router, I’d pick OPNsense.
What firewall rules do I need for a WireGuard client tunnel?
Three places: WAN (allow outbound UDP 51820 if your rules are restrictive), the WG_VPS interface (allow traffic from WG net), and LAN (policy route via WG gateway under Advanced). Plus outbound NAT if you’re doing a full tunnel.
What MTU should I use for WireGuard over PPPoE or VLAN?
Start with 1412. WireGuard adds 60 bytes overhead. PPPoE subtracts 8 from the standard 1500. Test with ping -s 1384 -M do 10.10.10.1 and increase only if it passes. Lower is safer than higher.
How do I route only specific LAN devices through the VPS tunnel?
Create an alias containing the IPs or subnets you want to route. Add a LAN firewall rule with that alias as the source and WG_VPS_GW as the gateway. Leave the default LAN rule below it for everything else.
AllowedIPs 0.0.0.0/0 on client: full tunnel or split?
On the client side, 0.0.0.0/0 in AllowedIPs means “send everything through the tunnel.” Whether your LAN actually uses it depends on your policy routing rules. You control which traffic goes through the tunnel with firewall rules, not AllowedIPs alone.
Auto-routes vs static routes in OPNsense WireGuard?
If “Disable Routes” is unchecked, OPNsense auto-creates routes based on AllowedIPs. That works for simple setups. For multi-subnet or multi-peer environments, check “Disable Routes” and manage everything manually through System > Routes. You get more control and fewer surprises.
Wrapping Up
The tunnel coming up is not the hard part. Routing is.
If you remember three things:
- Assign the WireGuard interface
- Use policy-based routing on LAN rules
- Fix asymmetric routing with outbound NAT (or proper VPS-side routes)
Once those are correct, everything clicks.
OPNsense makes this easier than expected once you understand where routing decisions happen. pfSense gets you there too, with a few extra steps around gateway monitoring and package management.
If you’re building a serious homelab, mastering this setup unlocks:
- Secure VPS reverse proxy
- Clean WireGuard port forwarding
- Multi-VLAN routing
- Dual-WAN failover via tunnel
- Encrypted site-to-site networking
Next step: experiment with gateway groups and failover tunnels.
That’s where things get fun.
This is Part 3 of a 3-part series on building a VPS-fronted homelab.
- Part 1: Why Your Homelab Needs a VPS to Share Services Publicly
- Part 2: How to Install WireGuard on a VPS and Connect It to Your Homelab
- Part 3: WireGuard Client on OPNsense and pfSense: LAN Routing for Your VPS Tunnel (this post)