WireGuard is the simplest way to join two office or datacentre networks behind different firewall platforms. The protocol is identical on both sides, the configuration fits on a napkin, and the tunnel comes up in milliseconds after the first handshake. The two projects expose it differently, though: pfSense CE 2.9 ships WireGuard as an installable package with tunnels and peers, while OPNsense 26.7 has it built into the core under VPN » WireGuard with instances and peers. This tutorial connects 10.10.0.0/24 behind pfSense to 10.20.0.0/24 behind OPNsense using a /30 transit network.
Table of Contents
Short answer: Create a WireGuard tunnel on each firewall with its own private key, listening on UDP 51820, and a transit address of 10.255.0.1/30 on pfSense and 10.255.0.2/30 on OPNsense. Add the other side as a peer with its public key, endpoint and allowed IPs covering both the transit /30 and the remote LAN, assign the WireGuard interface, allow UDP 51820 on WAN and the remote subnet on the tunnel interface, then confirm a recent handshake under the status page on each side.
Plan addresses and open the port
Pick a transit subnet that does not exist anywhere else in either organisation. Decide which side is reachable on a fixed public address; the other can sit behind a dynamic address as long as it initiates and uses a persistent keepalive. Both firewalls need a WAN rule allowing UDP 51820 from the peer’s public address, or from any if one side is dynamic.
pfSense side
Install the WireGuard package from System » Package Manager » Available Packages. Then go to VPN » WireGuard » Tunnels and add a tunnel: description to-opnsense, listen port 51820, generate a key pair and note the public key, and set the interface address to 10.255.0.1/30. Save and enable WireGuard on the Settings tab.
Under VPN » WireGuard » Peers add a peer bound to that tunnel: the OPNsense public key, endpoint address and port 51820, a keepalive of 25 seconds, and allowed IPs of 10.255.0.0/30 and 10.20.0.0/24. Allowed IPs act as both a routing table and an ingress filter, so a missing entry silently drops traffic.
Assign the tunnel as an interface under Interfaces » Assignments, enable it with IPv4 type None (the tunnel already carries the address), and add a static route under System » Routing » Static Routes for 10.20.0.0/24 via a gateway you create on the WireGuard interface pointing at 10.255.0.2. Finally add firewall rules: on WAN allow UDP 51820 from the OPNsense public IP, and on the new WireGuard interface allow traffic from 10.20.0.0/24 to 10.10.0.0/24.
OPNsense side
Go to VPN » WireGuard » Instances and add one: name to-pfsense, generate keys, listen port 51820, tunnel address 10.255.0.2/30. Under Peers add the pfSense public key, endpoint and port, allowed IPs 10.255.0.0/30 and 10.10.0.0/24, keepalive 25. Tick the instance’s peer list to include this peer and enable WireGuard on the Settings tab.
Assign the wg0 device under Interfaces » Assignments, enable it, and create a gateway under System » Gateways » Configuration on that interface with address 10.255.0.1. Add a route under System » Routes for 10.10.0.0/24 via that gateway. Under Firewall » Rules add a WAN rule for UDP 51820 from the pfSense address and a rule on the WireGuard interface allowing 10.10.0.0/24 to 10.20.0.0/24.
Verify the handshake
On pfSense, VPN » WireGuard » Status shows each peer with the time of the latest handshake and transfer counters. On OPNsense the equivalent is VPN » WireGuard » Status. From the shell on either box:
wg show
ping -c 3 10.255.0.2
ping -c 3 -S 10.10.0.1 10.20.0.1
The second ping tests the transit link, the third tests LAN-to-LAN routing by sourcing from the firewall’s LAN address. If the handshake never appears, the keys are swapped, the port is blocked, or the endpoint is wrong; a handshake with no LAN reachability usually means an allowed-IPs or firewall-rule gap.
Common pitfall and keeping it healthy
The classic mistake is pasting a private key into the peer’s public-key field, which fails silently. Copy public keys only from the status page of the other firewall. A second trap is overlapping subnets at the two sites; WireGuard cannot fix that and you will need 1:1 NAT on one side. For tunnel performance issues see Troubleshoot MTU, fragmentation and slow VPN throughput; a WireGuard MTU of 1420 is a safe default over a 1500-byte WAN. Rotate keys when staff with firewall access leave, and keep both firewalls on current releases.
Site-to-site WireGuard at a glance

Official documentation: WireGuard quick start, OPNsense documentation, pfSense documentation.
Related guides: Install pfSense CE 2.9 step by step with the network installer and ZFS · Troubleshoot MTU, fragmentation and slow VPN throughput · Set up HAProxy reverse proxy with Let’s Encrypt (ACME) on pfSense.
Frequently asked questions
Does WireGuard between pfSense and OPNsense need a static IP on both ends?
No. One side must have a stable address or DNS name to act as the endpoint; the other can be dynamic and simply initiates with a persistent keepalive so the tunnel stays up through NAT.
How long does a pfSense to OPNsense WireGuard setup take?
With addresses planned in advance, about thirty minutes for both sides including firewall rules and testing. Most of the time goes into exchanging public keys accurately.
Can I undo the tunnel without leaving remnants?
Yes. Disable and delete the peer, the interface assignment, the gateway, the static route and the firewall rules on each side, then remove the tunnel or instance. On pfSense you can also uninstall the WireGuard package.