Skip to main content
RunBook Academy

← All labs in OPNsense

Lab · advanced · ~120 min

Lab: Build an IPsec site-to-site tunnel between two OPNsense routers

B · Nested virtualisationC · Simulation

Objectives

  • Configure an IKEv2 Phase 1 with PSK, AES-256-GCM and SHA-256
  • Define a Phase 2 that covers both LAN subnets
  • Add firewall rules on the IPsec interface so traffic can pass
  • Confirm both ends see `ESTABLISHED` on Phase 1 and `INSTALLED` on Phase 2
  • Prove traffic flows across the tunnel with a ping from each LAN to the other

Prerequisites

This lab builds an IPsec site-to-site tunnel between two OPNsense routers using IKEv2 with pre-shared keys. By the end you will have a working tunnel that encrypts traffic between two LANs, with both ends reporting ESTABLISHED on Phase 1 and INSTALLED on Phase 2.

The lab is symmetric. The same set of steps runs on both routers, with one column of values that differs between ends (the remote IP, the remote LAN). Use a notebook or two terminals side-by-side to keep the local and remote columns straight.

Objective

By the end of this lab, you can:

  • Configure an IKEv2 Phase 1 with PSK, AES-256-GCM and SHA-256.
  • Define a Phase 2 covering two local-and-remote subnets.
  • Add the firewall rules needed for IPsec to terminate and pass traffic.
  • Read ipsec statusall to confirm Phase 1 is ESTABLISHED and Phase 2 is INSTALLED.
  • Run a ping across the tunnel from each side and confirm the ESP traffic on the WAN.

Requirements

You need:

  • Two OPNsense instances — call them OPN-A and OPN-B.
  • A WAN link between them. In nested mode, this is a host-only network shared by both firewalls.
  • A LAN behind each. OPN-A LAN is 10.10.10.0/24; OPN-B LAN is 10.10.20.0/24.
  • A host on each LAN that can ping. The DHCP-scope lab’s reservation scheme gives you a stable target on each side.
  • Outbound UDP/500 and UDP/4500 plus IP protocol 50 (ESP) between the two WANs. Confirm before troubleshooting.
SideHostnameWAN IPLAN subnetLAN gateway
AOPN-A198.51.100.110.10.10.0/2410.10.10.1
BOPN-B198.51.100.210.10.20.0/2410.10.20.1

Tasks

Task 1: Lay out the parameters

Write the parameters down before opening the GUI. The most common IPsec failure is a Phase 2 mismatch where one end has 10.10.10.0/24 ↔ 10.10.20.0/24 and the other has the source and destination reversed.

Phase 1 (IKE SA):
  Remote gateway  : 198.51.100.1  (the other side's WAN)
  Authentication  : Pre-Shared Key
  PSK             : <32+ random bytes>
  Encryption      : AES-256-GCM
  Integrity       : SHA-256 (or GCM-internal, since GCM is AEAD)
  DH group        : 14 (2048-bit MODP)
  Lifetime        : 28800 s (8h)
  Version         : IKEv2
  DPD             : enabled, 10s delay, 60s timeout
  NAT-T           : enabled

Phase 2 (CHILD SA):
  Local subnet    : 10.10.10.0/24   (side A) | 10.10.20.0/24 (side B)
  Remote subnet   : 10.10.20.0/24   (side A) | 10.10.10.0/24 (side B)
  Encryption      : AES-256-GCM
  PFS             : group 14
  Lifetime        : 3600 s (1h)

Generate a strong PSK once and use the same string on both ends:

# On a Linux host, or on either OPNsense shell
openssl rand -base64 48

Paste that into both routers’ Phase 1 PSK fields. If the strings differ by even one character, the IKE_AUTH exchange fails with AUTHENTICATION_FAILED and the logs are not helpful about which end has the wrong string.

Task 2: Enable IPsec on both routers

VPN → IPsec → Tunnel Settings on each router:

FieldValue
Enable IPsecon
Prefer older IPsec SAsoff (default; safer)
Disable auto-addoff (lets strongSwan install SPDs)

Save. The daemon (charon) is enabled but no tunnel exists yet.

Task 3: Configure Phase 1 on both routers

VPN → IPsec → Phase 1 → + Add on OPN-A:

FieldValue
Connection methodDefault
Key Exchange versionIKEv2
Internet ProtocolIPv4
InterfaceWAN
Remote gateway198.51.100.2
Descriptionto OPN-B
Authentication MethodPre-Shared Key
My identifierMy IP address (198.51.100.1)
Peer identifierPeer IP address (198.51.100.2)
Pre-Shared Key(paste the PSK from Task 1)
Encryption algorithmAES-256-GCM
Hash algorithmSHA-256
DH Group14
Lifetime28800
Rekey time(blank — use lifetime)
Reauth time(blank)
DPDenabled; delay 10, timeout 60, action restart
NAT Traversalenabled

On OPN-B, the symmetric configuration with the local/remote columns swapped:

FieldValue
Remote gateway198.51.100.1
My identifierMy IP address (198.51.100.2)
Peer identifierPeer IP address (198.51.100.1)
(everything else identical)

Save and apply on each. Confirm charon saw the change:

# On each OPNsense
ipsec statusall

You should see IKE_SA to the remote IP, status STATE_V2_CONNECTING or ESTABLISHED. If you see no row at all, charon did not load the config — restart the daemon:

ipsec restart

Task 4: Configure Phase 2 on both routers

VPN → IPsec → Phase 2 → + Add on OPN-A:

FieldValue
ModeTunnel
Descriptionto-OPN-B-LAN
Local subnet typeLAN subnet
Local subnet10.10.10.0/24
Remote subnet typeNetwork
Remote subnet10.10.20.0/24
Encryption algorithmAES-256-GCM
Hash algorithmSHA-256 (or AEAD-only if GCM)
PFS group14
Lifetime3600

On OPN-B, the symmetric configuration:

FieldValue
Local subnet10.10.20.0/24
Remote subnet10.10.10.0/24

Apply on both ends.

Task 5: Firewall rules on the IPsec interface

The IPsec interface on OPNsense is a group interface. By default it has no rules; traffic that arrives from the tunnel is dropped before Phase 2 can route it.

On each OPNsense: Firewall → Rules → IPsec:

ActionSourceDestinationProtocol
pass10.10.10.0/2410.10.20.0/24any
pass10.10.20.0/2410.10.10.0/24any

These mirror the Phase 2 selectors. In production, tighten per-port and per-host.

Confirm:

pfctl -sr | grep -A1 'ipsec'

Task 6: Trigger the tunnel and watch the negotiation

From a host on OPN-A’s LAN, ping a host on OPN-B’s LAN:

ping -c 4 10.10.20.50

The first ping triggers Phase 2 negotiation; expect 1-3 seconds of latency on the first echo. Subsequent pings should be sub-millisecond after the SA is installed.

On OPN-A, watch the negotiation:

tail -f /var/log/charon.log

You should see:

... IKE_SA to-OPN-B[1] established between 198.51.100.1[198.51.100.1]...198.51.100.2[198.51.100.2]
... CHILD_SA to-OPN-B-LAN{1} established with SPIs ...
... sending DPD vendor ID
... received DPD vendor ID

Task 7: Read the SA table

The ipsec statusall output is the authoritative answer:

ipsec statusall

A healthy tunnel looks like:

Routed Connections:
  to-OPN-B{1}:  198.51.100.1[198.51.100.1]...198.51.100.2[198.51.100.2]  IKEv2
  to-OPN-B-LAN{2}:  10.10.10.0/24 === 10.10.20.0/24

Security Associations (1 up, 0 connecting):
  to-OPN-B[1]:  ESTABLISHED 5 minutes ago, ...
  to-OPN-B-LAN{2}:  INSTALLED, ESP in UDP SPIs: ...

Two things to look for:

  1. The routed connection lists both ends and the IKE version.
  2. The CHILD_SA is INSTALLED, not rekeying or empty.

If Phase 1 is ESTABLISHED but Phase 2 is missing, the Phase 2 proposal does not match. If Phase 2 shows rekeying repeatedly, the PFS group or the lifetime is misaligned.

Task 8: Capture ESP on the wire

The signature of a working IPsec tunnel is bidirectional ESP traffic on the WAN. Capture from OPN-A’s WAN:

sudo tcpdump -i em0 -nn -s 0 -c 50 proto 50 or udp port 500 or udp port 4500

While the capture runs, ping across the tunnel from a host on OPN-A’s LAN. You should see:

  • A burst of UDP/500 and UDP/4500 packets as the SA is established or rekeyed.
  • A stream of ESP packets (IP protocol 50, no visible port) carrying the encrypted traffic.

If the capture shows only IKE packets (UDP/500 and UDP/4500) and no ESP, the negotiation never finished Phase 2. If the capture shows only outbound ESP with no reply, the IPsec firewall rule on the remote side is dropping the return.

Task 9: Verify both directions

The bidirectional check is the trap-proof evidence. From each LAN, ping the other:

# From a host on OPN-A's LAN
ping -c 4 10.10.20.50

# From a host on OPN-B's LAN
ping -c 4 10.10.10.50

Both must succeed. If one direction works and the other does not, the issue is asymmetric — usually a missing firewall rule on one end, or a Phase 2 selector that covers only one direction.

Task 10: Test rekeying

Rekeying is where IKEv2 shows its advantage over IKEv1. Drop the SA and watch it rebuild:

# On OPN-A
ipsec down to-OPN-B-LAN
ipsec up   to-OPN-B-LAN

A clean rekey shows a new CHILD_SA with new SPIs in ipsec statusall and no errors in charon.log. If rekeying fails after a lifetime expiry, your PFS group or lifetime is mismatched with the peer — both ends must agree on PFS group or the rekeyed SA will not be accepted.

Validation

  • ipsec statusall on both ends shows IKE_SA ESTABLISHED and CHILD_SA INSTALLED.
  • A ping from a host on OPN-A’s LAN to OPN-B’s LAN succeeds.
  • A ping from a host on OPN-B’s LAN to OPN-A’s LAN succeeds.
  • tcpdump -i em0 proto 50 shows ESP traffic during a cross-tunnel ping.
  • charon.log shows no errors during a clean rekey.
  • pfctl -sr | grep ipsec shows the firewall rules.

Expected Result

An IPsec site-to-site tunnel between OPN-A and OPN-B that encrypts traffic between 10.10.10.0/24 and 10.10.20.0/24. Both routers report Phase 1 ESTABLISHED and Phase 2 INSTALLED. A ping from either LAN reaches the other. Rekeying after the Phase 2 lifetime works without operator intervention.

Troubleshooting

Phase 1 stays in CONNECTING. UDP/500 or UDP/4500 is being blocked between the WANs. Confirm with tcpdump -i em0 port 500 — you should see at least one outbound packet from OPN-A. If the capture shows outbound only, check upstream firewalls and OPNsense’s WAN firewall rule for UDP/500 and UDP/4500 inbound.

Phase 1 establishes, Phase 2 fails with NO_PROPOSAL_CHOSEN. The Phase 2 encryption/hash/PFS/lifetime does not match. Diff the GUI on both ends. AES-256-GCM on one end and AES-256-CBC on the other will not negotiate; SHA-256 on one and SHA-384 on the other will not negotiate.

Phase 1 and Phase 2 establish, but ping times out. The IPsec interface on one end has no firewall rule. Confirm pfctl -sr | grep ipsec on both ends.

Tunnel works for 60 minutes, then drops. Phase 2 lifetime expiry, but the rekey is failing. Confirm both ends have the same lifetime and PFS group. Watch charon.log during a rekey window.

Ping works from one direction only. A firewall rule is missing on one end, or the LAN host on the broken side has no route back through OPNsense. Confirm routing with netstat -rn or ip route get 10.10.20.50 from the LAN host.

MTU-related packet loss or fragmentation. IPsec adds 50-90 bytes of overhead (ESP + IP + UDP-encap + padding). Symptoms: ping works for small packets, fails for larger ones; web loads partially. Reduce the WAN MTU to 1400 or set the MSS clamp on the LAN firewall rule to 1380.

Cleanup

Tear down both ends and verify.

# On each OPNsense shell
ipsec down to-OPN-B-LAN
ipsec down to-OPN-B

# Then via GUI:
# VPN → IPsec → Phase 1 → delete both entries
# VPN → IPsec → Phase 2 → delete both entries
# VPN → IPsec → Tunnel Settings → uncheck Enable IPsec → Apply

# Confirm no SAs are left
ipsec statusall

# Remove the firewall rules
# Firewall → Rules → IPsec → delete both rules

# Confirm the IPsec firewall group has no rules
pfctl -sr | grep -E 'ipsec|10.10.10.0|10.10.20.0' || \
    echo "no IPsec rules left"

The PSK lives in /usr/local/etc/swanctl/conf.d/*.conf and is not exported in plaintext config.xml. Wipe the file or move the firewall out of service to clear the secret.

What you learned

  • IPsec site-to-site is a symmetric configuration. Each end fills Phase 2 from its own perspective, and the two ends agree on encryption, hash, PFS, and lifetime.
  • IKEv2 rekeys silently in the background; the SA on the wire changes without dropping traffic. The trap is that rekeying reveals configuration drift that a one-shot negotiation might tolerate.
  • The IPsec interface is a group interface with no default rules. Even a fully-negotiated tunnel will not pass traffic until the firewall rules on both ends are in place.
  • MTU and MSS matter. ESP adds overhead that breaks large packets; reduce MTU or clamp MSS to compensate.

Deliverables

  • · A working IPsec tunnel between two OPNsense instances
  • · Phase 1 and Phase 2 SA entries on both ends
  • · Firewall rules on the IPsec tab on both ends
  • · Captured IKE_AUTH and ESP traffic between the two WANs

Verification status

Last reviewed
2026-08-14
Executed end to end
not yet run on hardware

The commands and configuration here have been reviewed against the verified software versions, but nobody has run this lab start to finish on a system meeting its prerequisites. Treat the Expected Outcome as the intended result rather than an observed one, and keep the Cleanup section to hand.