Skip to main content
RunBook Academy

OPNsenseXXI · WireGuardWireGuard

WireGuard troubleshooting — diagnosing tunnels that do not come up

Advanced⏱ ~15 minwgifconfignetstattcpdumppfctlping

What you'll learn

  • Apply a layered diagnostic sequence to WireGuard failures
  • Identify handshake failures (key mismatch, endpoint wrong, transport blocked)
  • Recognise AllowedIPs failures (overlap, authorisation, routing)
  • Diagnose firewall and NAT failures (rules, NAT, policy routing)
  • Use packet capture, wg show, pfctl and the routing table as evidence

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

Not yet marked complete on this device.

WireGuard tunnels fail in five layers: the handshake (key or endpoint mismatch), the transport (UDP blocked, NAT not handled), the AllowedIPs (overlap, wrong subnet, authorisation), the firewall (rules, NAT), or the routing (no route, policy-routing theft). The diagnostic discipline is to identify which layer the failure is in before changing anything, and to read the evidence — wg show, packet capture, pfctl, the routing table — together rather than from any single source.

This lesson covers the diagnostic sequence, the evidence each layer produces, and the most common production failures with their fixes.

The diagnostic sequence

The five layers of a WireGuard failure, ordered from the lowest to the highest:

  1. Handshake — does wg show show a recent handshake timestamp?
  2. Transport — are UDP 51820 packets reaching the firewall from the peer’s public IP?
  3. AllowedIPs — does the routing table show the expected routes for the peer’s AllowedIPs?
  4. Firewall — do the firewall rules on the WireGuard interface and the relevant interfaces permit the traffic?
  5. Routing — does the firewall’s routing table correctly direct traffic to the tunnel?

The discipline: walk the layers in order. Each layer produces evidence that the next layer consumes. Do not start with packet capture (the most detail, the least signal) — start with wg show (the least detail, the most signal for the handshake layer).

Layer 1: handshake

The handshake is the first thing to check. If the handshake is not completing, no traffic flows; if the handshake is completing but traffic is broken, the problem is elsewhere.

The evidence: wg show wg0 shows the latest handshake timestamp for each peer.

Read-only / Safewg show handshake
$ wg show wg0
interface: wg0
public key: serverpubkey...=
private key: (hidden)
listening port: 51820

peer: siteBpublickey...=
endpoint: 203.0.113.1:51820
allowed ips: 10.1.0.0/24
latest handshake: 1 minute, 23 seconds ago
transfer: 245.8 MiB received, 78.4 MiB sent

Illustrative output

Handshake never completes. The most common causes:

CauseEvidenceFix
Key mismatchBoth sides have handshake attempts but no completionCompare public keys on both sides (wg show on each); correct the mismatched key
Endpoint wrongThe firewall’s logs show outgoing UDP to the wrong addressCorrect the endpoint on the peer entry
Transport blockedNo outgoing UDP at all on the WANFix the WAN firewall rule (allow UDP 51820 from the peer’s public IP)
Clock skewBoth sides have correct keys but handshake fails with weird errorsVerify NTP is synchronised on both firewalls

The key mismatch is the most common. The diagnostic is to compare the public keys on both sides — wg show wg0 on Site A should show Site B’s public key in the peer entry, and vice versa. A typo in the public key (even one character) breaks the handshake silently.

Handshake completes but no transfer. The handshake is establishing; the session keys are valid; the tunnel is up. If transfer counters stay at zero, the firewall is sending packets but no return traffic is coming back. The most likely cause is the AllowedIPs configuration: the firewall is sending traffic to the peer’s inner IP, but the peer is dropping it because the inner source IP is not in the peer’s AllowedIPs.

Layer 2: transport

The transport is the UDP packets between the two endpoints. If the transport is blocked, no handshake completes; if the transport is asymmetric, the handshake may complete but traffic may flow in one direction only.

The evidence: tcpdump -ni igb1 'udp port 51820' on each firewall.

A working transport shows UDP packets in both directions. A broken transport shows no packets, packets in one direction only, or packets to the wrong address.

Transport blocked. The WAN firewall rule does not allow UDP 51820 from the peer’s public IP. The fix is to add the rule:

pass in on igb1 inet proto udp from 203.0.113.1 to 198.51.100.1 port 51820 keep state

Transport asymmetric. The firewall sends UDP to the peer, but the peer’s replies are blocked by an intermediate firewall (corporate network, ISP, country-level firewall). The diagnostic is packet capture on both sides; if one side sees outgoing packets and no incoming packets, the path is asymmetric.

Endpoint behind NAT. One side is behind NAT and the keepalive is not configured. The fix is to set persistent keepalive = 25 on the peer entry on the NAT’d side.

Layer 3: AllowedIPs

AllowedIPs failures are the most common silent production failures. The handshake completes; the transport flows; but no user traffic reaches the remote subnet.

The evidence: netstat -rn | grep wg0 shows the routing table; tcpdump -ni wg0 shows the inner traffic.

AllowedIPs mismatch. Each side’s AllowedIPs is supposed to be the other side’s LAN subnet. If Site A’s AllowedIPs is set to Site A’s own subnet (10.0.0.0/24 instead of 10.1.0.0/24), the firewall routes traffic for 10.0.0.0/24 to the WireGuard interface — a routing loop or a black hole.

The fix: verify AllowedIPs on both sides match the other side’s LAN subnet.

AllowedIPs overlap. Two peers with the same AllowedIPs produce ambiguous routing. The kernel picks one route; the other peer’s traffic is silently dropped. The fix: every peer’s AllowedIPs must be unique.

AllowedIPs too broad. A peer’s AllowedIPs is 0.0.0.0/0 when the operator intended a specific subnet. The peer is authorised for all traffic; routing for all VPN-destined traffic goes through this peer. The fix: set AllowedIPs to the actual subnet.

Layer 4: firewall

The firewall rules determine whether VPN traffic reaches internal subnets. Even with a perfect handshake, transport, and AllowedIPs configuration, traffic is blocked if the firewall rules do not permit it.

The evidence: pfctl -s rules | grep wg0 shows the rules on the WireGuard interface.

No allow rule on the WireGuard interface. Default deny blocks the traffic. The fix: add an explicit allow rule for the remote subnet.

Rule on the wrong interface. The operator writes a rule on the LAN interface for VPN traffic, but the traffic arrives on the WireGuard interface. The rule never matches. The fix: rules for VPN traffic go on the WireGuard interface (for inbound) and on the LAN interface (for outbound).

NAT missing for full-tunnel. Full-tunnel VPN users can reach internal subnets but not the Internet. The fix: add an outbound NAT rule for the VPN pool on the WAN interface.

Layer 5: routing

The firewall’s routing table directs traffic to the tunnel interface. If the routing table has no route for the remote subnet, traffic is dropped at the routing layer.

The evidence: netstat -rn | grep -E 'wg0|<remote subnet>' shows the routes for the tunnel interface and the remote subnet.

No route for the remote subnet. The AllowedIPs is configured but the route is not installed. This happens when the WireGuard interface is administratively down or when the AllowedIPs configuration did not apply. The fix: verify the interface is up (ifconfig wg0) and the AllowedIPs is saved (wg show wg0 allowed-ips).

Policy-routing theft. A multi-WAN LAN-to-any rule matches VPN-destined traffic and tries to send it through the WAN gateway. The fix: add a before-rule for the remote subnet with gateway = default.

A walkthrough: tunnel comes up but traffic does not flow

A typical diagnostic walkthrough:

  1. wg show wg0 shows a recent handshake. Layer 1 is consistent — the handshake completed.
  2. tcpdump -ni igb1 'udp port 51820' shows packets in both directions. Layer 2 is consistent — the transport flows.
  3. netstat -rn | grep 10.1.0 shows a route to 10.1.0.0/24 via wg0. Layer 3 (AllowedIPs) and layer 5 (routing) are consistent — the route exists.
  4. tcpdump -ni wg0 host 10.1.0.50 shows no traffic. Layer 4 (firewall) is suspect — the inner traffic is not arriving at the firewall.
  5. pfctl -s rules | grep wg0 shows default deny and no allow rule. The firewall is blocking the traffic. The fix is to add an allow rule on the WireGuard interface for the remote subnet.

A failure at any step narrows the cause. Step 1 fails → keys or endpoint. Step 2 fails → transport or WAN rule. Step 3 fails → AllowedIPs configuration. Step 4 fails → firewall rules. Step 5 fails → routing table.

Common WireGuard failures

Ten failures appear repeatedly:

  1. Key mismatch. Both sides have the wrong public key. Fix: compare keys on both sides.
  2. Endpoint wrong. The endpoint IP or port is incorrect. Fix: verify the endpoint matches the remote firewall’s public IP and listening port.
  3. UDP 51820 blocked on WAN. No WAN rule for the transport. Fix: add the WAN rule.
  4. AllowedIPs overlap. Two peers with the same AllowedIPs. Fix: unique AllowedIPs per peer.
  5. No firewall rule on the WireGuard interface. Default deny blocks the traffic. Fix: add the allow rule.
  6. NAT missing for full-tunnel. Internal subnets reachable, Internet not. Fix: add outbound NAT for the VPN pool.
  7. Policy-routing theft. Multi-WAN LAN-to-any rule sends VPN traffic through the WAN gateway. Fix: add before-rule for the VPN subnet.
  8. MTU mismatch. Large packets fail silently. Fix: configure tunnel MTU and source MTU explicitly.
  9. Clock skew. Both sides have correct keys but handshake fails. Fix: verify NTP on both sides.
  10. NAT timeout without keepalive. Endpoint behind NAT, no persistent keepalive. Fix: set keepalive = 25.

Summary

  • WireGuard failures are in one of five layers: handshake, transport, AllowedIPs, firewall, routing.
  • The diagnostic sequence walks the layers in order, each layer producing evidence that the next layer consumes.
  • A recent handshake is not the same as a working tunnel — it confirms key exchange but not traffic flow.
  • The routing table is the final arbiter — if the route is wrong, no firewall rule fixes the problem.
  • The ten common failures cover most production incidents; each has a known fix and a known diagnostic.

Knowledge check · 4 questions

  1. Q1. A WireGuard site-to-site tunnel shows no handshake timestamp for the peer on either side. The configuration appears correct. What is the most likely cause?

  2. Q2. A WireGuard tunnel with a recent handshake but zero transfer counters shows the session keys are fine and that the problem is upstream of the crypto: no user traffic is reaching the tunnel.

  3. Q3. Which of the following are valid diagnostic steps for a WireGuard failure? Select all that apply.

  4. Q4. A WireGuard full-tunnel remote-access deployment connects successfully; users can reach internal subnets but cannot reach external websites. The AllowedIPs is 0.0.0.0/0. What is the most likely cause?

Passing score: 75%. Answers are checked in this browser.