VPN
Build a site-to-site IPsec VPN
Establish an IPsec tunnel to another firewall and route traffic across it.
Why it differs: The IPsec parameters are standards-based and identical everywhere, but the model around them is not: route-based (a virtual interface you route into) versus policy-based (selectors decide what enters the tunnel). Mixing the two between sites is the classic reason a tunnel comes up in phase 1 and never passes traffic.
Router / switch / AP
MikroTik RouterOS
GUI or CLIWritten against RouterOS 7.x
Steps
- Profile (phase 1 proposal):
/ip ipsec profile add name=to-branch enc-algorithm=aes-256 hash-algorithm=sha256 dh-group=modp2048 - Peer:
/ip ipsec peer add name=branch address=203.0.113.20 profile=to-branch exchange-mode=ike2 - Identity (auth):
/ip ipsec identity add peer=branch auth-method=pre-shared-key secret="<psk>" - Proposal (phase 2):
/ip ipsec proposal add name=to-branch enc-algorithms=aes-256-cbc auth-algorithms=sha256 pfs-group=modp2048 - Policy (selectors):
/ip ipsec policy add src-address=192.168.88.0/24 dst-address=192.168.99.0/24 tunnel=yes peer=branch proposal=to-branch - Exclude the tunnel from NAT — add above your masquerade rule:
/ip firewall nat add chain=srcnat action=accept src-address=192.168.88.0/24 dst-address=192.168.99.0/24 place-before=0 - GUI: IP → IPsec with a tab per object. Verify:
/ip ipsec active-peers print and /ip ipsec policy print
Gotchas & notes
- The NAT exclusion is the number one MikroTik IPsec failure. Your masquerade rule rewrites the source address before the IPsec policy can match it, so the tunnel establishes and no traffic ever uses it. Add the
action=accept srcnat rule *above* the masquerade rule. - RouterOS IPsec is policy-based by default: five separate objects (profile, peer, identity, proposal, policy) that must be internally consistent. Any mismatch shows as a phase 1 or phase 2 failure in
/log print with topics=ipsec. - Allow the protocols in the
input chain: UDP/500, UDP/4500, and IP protocol 50 (ESP). A default drop rule blocks the tunnel silently. - For a route-based tunnel that interoperates cleanly with FortiGate/PAN-OS, some designs prefer IPsec over a GRE/IPIP tunnel rather than fighting policy mode.
/log print where topics~"ipsec" is the only way to debug this — the status flags alone will not tell you which proposal mismatched.
Vendor documentation ↗NGFW / router
Fortinet FortiGate (FortiOS)
GUI or CLIWritten against FortiOS 7.2 – 7.6
Steps
- VPN → IPsec Wizard → *Site to Site* → follow the prompts (remote gateway, PSK, local/remote subnets). The wizard creates the phase 1, phase 2, static routes, address objects, and both firewall policies.
- Manual route-based: VPN → IPsec Tunnels → Create New → Custom → configure Phase 1 (remote gateway, IKE version, proposals, PSK) and Phase 2 (selectors, PFS).
- Add static routes pointing the remote subnet at the tunnel interface, and firewall policies in both directions (LAN→tunnel and tunnel→LAN).
- Verify: Dashboard → Network → IPsec widget, or
diagnose vpn tunnel list and diagnose vpn ike gateway list.
Gotchas & notes
- Use the wizard for the first tunnel. It generates the two firewall policies and the static route that people forget when building it manually — a phase-2-up tunnel with no policies looks broken but is fine.
- FortiGate is route-based: the tunnel becomes a virtual interface you route into. Peering with a policy-based device (older RouterOS/Cisco) requires setting the phase 2 selectors to match exactly, or the remote end rejects the SA.
- The tunnel interface needs its own firewall policies in both directions. Traffic LAN→VPN and VPN→LAN are separate policies, and the return one is the one usually missing.
- Do not enable NAT on the VPN policies — that translates traffic into the tunnel and the remote end drops it as an unexpected source.
diagnose debug application ike -1 plus diagnose debug enable gives the real negotiation log. Remember diagnose debug disable afterwards.- For dial-up/dynamic-IP remote ends, set the remote gateway to *Dialup User* and expect the initiating side to be the one with a dynamic address.
Vendor documentation ↗Controller-managed gateway / switch / AP
Ubiquiti UniFi Network
GUIWritten against UniFi Network 8.x – 9.x (UDM / UDM-Pro / UXG)
Steps
- Settings → VPN → Site-to-Site VPN → Create New → choose *Manual IPsec* (or *Site Magic* for UniFi-to-UniFi).
- Set the remote gateway IP, the remote and local subnets, and the pre-shared key.
- Under *Advanced*, match the encryption, hash, DH group, and PFS to the far end exactly.
- Save; the gateway provisions. Status appears on the VPN page.
Gotchas & notes
- Site Magic (UniFi-to-UniFi, cloud-orchestrated) is easy and reliable but only works between UniFi gateways on the same Ubiquiti account. For anything third-party you need *Manual IPsec*.
- The Advanced parameter list is narrower than other vendors' — some proposal combinations a FortiGate or PAN-OS offers simply cannot be selected here, so you may have to weaken/adjust the far end to a UniFi-supported set.
- There is no negotiation log in the UI. Debugging a failing manual tunnel means SSH to the gateway and reading
swanctl --list-sas / ipsec statusall and the strongSwan logs — a big step down from the other platforms. - Route-based (VTI) support has varied by firmware; policy-based is the safer assumption for interop.
- Changing VPN settings reprovisions the gateway and drops the tunnel briefly.
Vendor documentation ↗Router / switch
Cisco IOS / IOS-XE
CLIWritten against IOS-XE 17.x (Catalyst 9000, ISR 1000/4000)
Steps
- Phase 1:
crypto ikev2 proposal PROP → encryption aes-cbc-256 → integrity sha256 → group 14; then an crypto ikev2 policy, crypto ikev2 keyring (with the peer and PSK), and crypto ikev2 profile. - Phase 2:
crypto ipsec transform-set TS esp-aes 256 esp-sha256-hmac → mode tunnel - Route-based (preferred):
interface Tunnel1 → ip address 10.255.0.1 255.255.255.252 → tunnel source Gi0/0 → tunnel mode ipsec ipv4 → tunnel destination 203.0.113.20 → tunnel protection ipsec profile PROF - Then route the remote subnet into
Tunnel1 and exclude the traffic from NAT with a deny at the top of the NAT ACL. - Verify:
show crypto ikev2 sa, show crypto ipsec sa, show interface Tunnel1
Gotchas & notes
- Exclude VPN traffic from NAT by adding a
deny for the interesting traffic at the top of your NAT ACL. Skipping this is the classic 'tunnel is up but nothing passes' cause on IOS, exactly as on MikroTik. - Prefer the VTI (
tunnel mode ipsec ipv4) route-based approach over legacy crypto maps: it gives you a real interface you can route, monitor, and apply features to. Crypto maps are still everywhere in old configs and are much harder to troubleshoot. - Set
ip mtu 1400 and ip tcp adjust-mss 1360 on the tunnel interface. Without them, large packets fail while ping and SSH work — a maddening, extremely common symptom. - IKEv2 needs matching proposals on both sides.
debug crypto ikev2 shows exactly which attribute mismatched; run it with a specific peer to limit output. copy running-config startup-config — everything above is lost on reload otherwise.
Vendor documentation ↗NGFW
Palo Alto Networks PAN-OS
GUI or CLIWritten against PAN-OS 10.2 / 11.x
Steps
- Create a Tunnel interface: Network → Interfaces → Tunnel → Add (
tunnel.1), assign a virtual router and a security zone. - Network → Network Profiles → IKE Crypto and IPsec Crypto — define the phase 1 and phase 2 proposals.
- Network → IKE Gateways → Add — peer address, IKE version, PSK, and the IKE Crypto profile.
- Network → IPsec Tunnels → Add — bind the tunnel interface, IKE gateway, and IPsec Crypto profile. Add Proxy IDs if the far end is policy-based.
- Add a static route for the remote subnet via
tunnel.1, plus security policies between the tunnel zone and your LAN zone in both directions. Commit. - Verify: Network → IPsec Tunnels status lights, or
show vpn ipsec-sa / show vpn ike-sa.
Gotchas & notes
- Proxy IDs are the interop trap. PAN-OS is route-based and defaults to 0.0.0.0/0 selectors; a policy-based peer (MikroTik, older Cisco, some UniFi) will reject that. Add Proxy IDs matching the far end's local/remote subnets exactly, or phase 2 fails while phase 1 succeeds.
- The tunnel interface must be in a zone and a virtual router, and you need security policies for tunnel-zone traffic. A tunnel showing green with no policies passes nothing.
- Enable Tunnel Monitor with a destination IP on the far side so the tunnel status reflects reality — without it, PAN-OS can show a tunnel as up when the remote LAN is unreachable.
- Everything needs a Commit, and committing IPsec changes renegotiates the tunnel (brief outage).
less mp-log ikemgr.log is the negotiation log; the GUI status is not detailed enough to debug a mismatch.
Vendor documentation ↗Router / firewall (FreeBSD)
Netgate pfSense CE
GUIWritten against pfSense CE 2.7 / Plus 24.x
Steps
- VPN → IPsec → Tunnels → Add P1 — set *Key Exchange*
IKEv2, *Remote Gateway*, *Authentication* Mutual PSK, identifiers, and the phase 1 encryption list. - Then Show Phase 2 Entries → Add P2 — set *Mode*
Tunnel IPv4, *Local Network*, *Remote Network*, and the phase 2 proposals. - Apply Changes, then add firewall rules on the IPsec interface tab to permit the tunnel traffic.
- For route-based, set P2 *Mode* to
Routed (VTI) and assign the VTI as an interface, then add static routes. - Verify: Status → IPsec, and Status → System Logs → IPsec for negotiation detail.
Gotchas & notes
- Firewall rules on the
IPsec tab are required — an established tunnel with no rules passes nothing inbound. This is the most common pfSense IPsec complaint. - Outbound NAT in Automatic mode generally does the right thing for policy-based (tunnel mode) IPsec, but with Manual/Hybrid outbound NAT you must ensure no rule NATs the VPN traffic.
- Choose deliberately between Tunnel IPv4 (policy-based, easy interop with MikroTik/Cisco crypto maps) and Routed VTI (route-based, matches FortiGate/PAN-OS). Do not mix modes across the two ends.
- Status → System Logs → IPsec gives readable strongSwan output naming the mismatched proposal — the best built-in IPsec debugging of the six.
- Set the phase 1 and phase 2 lifetimes to match the far end; mismatched lifetimes cause a tunnel that works then drops every few hours.
- If both ends are pfSense, consider WireGuard or OpenVPN instead — far less to get wrong.
Vendor documentation ↗NGFW
SonicWall (SonicOS)
GUIWritten against SonicOS 7.3.x (Gen7 TZ/NSa/NSsp; current General Release line is 7.3.2/7.3.3 — note Gen8 TZ80/TZ280+/NSa 2800+ hardware instead runs the separate SonicOS 8.x line)
Steps
- Manage → Connectivity → VPN → Base Settings, click Add under VPN Policies to create the tunnel.
- General tab: set IPsec Keying Mode to IKE using Preshared Secret (or IKEv2/certificates), name the policy, enter the peer's IPsec Primary Gateway Name or Address, and the shared secret.
- Network tab: pick the Local Networks and Remote Networks address objects. This is SonicWall's classic model — these are policy-based traffic *selectors*; only traffic matching them enters the tunnel, there's no virtual interface involved unless you deliberately choose Tunnel Interface mode below.
- Proposals tab: set the IKE (Phase 1) proposal — exchange mode, DH group, encryption, authentication, lifetime — and the IPsec (Phase 2) proposal — ESP, encryption, authentication, PFS group, lifetime. These must match the peer exactly.
- Advanced tab: enable options like Enable Keep Alive if you want the tunnel to stay up without traffic triggering it, and any NAT-over-VPN or multicast options needed.
- For a route-based tunnel instead: Manage → Network → Interfaces → Add Interface, create a Tunnel Interface, bind it to a VPN policy configured with Tunnel Interface keying, then point static (or dynamic) routes at it — closer to how MikroTik/pfSense-style route-based VPN works, but it's an explicit alternate mode, not the default.
- Verify: Manage → Connectivity → VPN → Base Settings shows a green icon and 'Currently Active' status for the policy, or check Investigate → Logs filtered on VPN. The CLI can only read status (
show vpn ipsec-sa, show vpn ike-info) — it cannot create or edit VPN policies.
Gotchas & notes
- SonicWall's default IPsec model is policy-based: explicit Local/Remote Network selectors per policy, not a routable virtual interface. Coming from a route-based vendor, the classic mistake is assuming any traffic destined for the peer's subnet will trigger the tunnel — if it doesn't exactly match the configured selectors, Phase 1 and Phase 2 can show green while traffic is silently dropped.
- Route-based VPN exists via Tunnel Interfaces, but it's a separate keying mode you must pick explicitly when creating the policy — it isn't the default and mixing a policy-based SonicWall against a route-based peer (or vice versa) is a common cause of a tunnel that negotiates but never passes real traffic.
- Address objects used as selectors must match on both ends. A SonicWall configured with a narrower or wider subnet than a Cisco/Fortinet/pfSense peer's selectors is the single most common 'Phase 2 up, zero traffic' failure mode.
- Configuration is GUI-only — the E-CLI has no commands to create or modify VPN policies; it only exposes read-only status/diagnostic output, consistent with SonicOS treating the CLI as a secondary tool.
- Check Manage → Network → NAT Policies if traffic still isn't entering the tunnel — a misordered NAT rule can rewrite source/destination before the packet ever reaches the VPN selector match.
Vendor documentation ↗Cloud-managed business routers, switches & Orbi Pro/WiFi APs
NETGEAR Insight (Cloud Management Platform)
GUIWritten against Insight Cloud Portal/App 10.0.x (cloud mgmt); switch-side CLI varies by line — Smart Switch "Lite CLI" firmware 6.0.10.5+/7.0.9.5+, fully-managed M4200/M4300 CLI 12.0.11.x
Steps
- Site-to-site VPN is a feature of the Insight-managed router / Orbi Pro line only — it does not exist on Insight-managed switches or standalone Orbi Pro access points. If your edge device is a BR200/BR500-class Insight router or an Orbi Pro WiFi 6/7 router unit, continue.
- In the Insight Cloud Portal (portal or mobile app): select the Organization → Location, open the router, go to VPN → Site-to-Site VPN → Add VPN Tunnel.
- Choose the peer type: Insight-managed peer (another device already enrolled in Insight — pick it from a list and Insight auto-provisions both ends, exchanging keys itself) or Third-party/Generic IPsec peer (manual mode for a non-NETGEAR firewall).
- For the generic/manual case, fill in: remote peer public IP, local and remote subnets (selectors), IKE version (IKEv1/IKEv2), pre-shared key, and Phase 1/Phase 2 encryption, hash, and DH group choices.
- Save — the portal pushes the tunnel config down to the router's actual gateway process; there is no local step on the device itself, and no CLI to check or adjust it afterward.
- Verify tunnel state from VPN → Site-to-Site VPN status column in the portal (up/down, last handshake) — there's no
show crypto equivalent to fall back on.
Gotchas & notes
- This is policy/selector-based only — you pick local and remote subnets, there is no virtual tunnel interface (VTI) to route into. If both sites are still on the factory-default 192.168.1.0/24 LAN, the tunnel will "connect" at Phase 1 but pass no traffic until one side is renumbered.
- The push-button "Insight-managed peer" mode only works between two devices enrolled in Insight (same or federated orgs) — Insight handles the key exchange itself. Peering with a Cisco/FortiGate/pfSense box on the other end forces you into the manual generic-IPsec path, which has noticeably fewer knobs (fewer DH groups, no configurable DPD interval) than a dedicated firewall's IPsec stack, so test the tunnel thoroughly before relying on it.
- Per the platform's cli_style, Insight-managed routers and Orbi Pro gateways have zero CLI — there is no SSH/console fallback if the cloud portal is unreachable, and no way to script or bulk-provision tunnels outside the GUI.
- VPN capability is limited to specific SKUs — plain consumer Nighthawk/Orbi (non-Pro) routers and Insight-managed switches cannot terminate a site-to-site tunnel at all, so confirm the exact model before designing a topology around this.
Vendor documentation ↗