HomeLabNetworkingSecurity

Packet by Packet Issue #1 | IPsec VPN Site-to-Site — Tunneling Between My Homelab and Anywhere

A practical walk-through of building an IPsec site-to-site VPN between a FortiGate hub and a MikroTik spoke — real configs, phase-by-phase explanations, and the number-one silent failure that trips up every first-time build.

22 June 2026·Michael Ndowora

Welcome back to Packet by Packet — the homelab networking newsletter that skips the textbook and gets straight into the terminal. If you've got gear spread across more than one location — a homelab at home, a VPS in the cloud, maybe a router at a family member's place — you've probably thought about stitching them into one coherent network. IPsec site-to-site VPNs are the grown-up way to do it. Not WireGuard (we'll get there), not OpenVPN, but the battle-tested, RFC-blessed, enterprise-standard protocol your FortiGate was practically born to run. This week we're building one from scratch.

How IPsec Actually Works (The Version That Sticks)

IPsec operates in two phases, and understanding this makes the whole thing click. Phase 1 (use IKEv2 — always IKEv2) is the handshake. The two peers prove their identities via a pre-shared key (PSK) or certificates, negotiate encryption and hashing algorithms, and establish a Security Association (SA) for the control channel. Phase 2 builds the actual data tunnel — another SA, this time scoped to the specific traffic you want to protect, defined by your "interesting traffic" selectors. The tunnel stays up as long as there's keepalive traffic or the SAs are renegotiated before they expire. Phase 1 SA lifetimes are typically 86,400 seconds (24 hours); Phase 2 is shorter — 3,600 seconds (1 hour) is common. If your tunnel drops overnight and comes back when you ping, expired Phase 2 SAs and misconfigured Dead Peer Detection (DPD) are your first suspects.

FortiGate as the Hub

On FortiGate, site-to-site tunnels live under VPN > IPsec Tunnels. The wizard gets you started, but the real control is in the custom settings. Key things to nail: set IKE version to v2, pick solid proposals (AES256 + SHA256 — skip the MD5 and DES relics), and set your remote gateway to the MikroTik WAN IP. FortiGate uses a route-based model, which means the tunnel surfaces as a virtual interface (named after your tunnel). You push routes out that interface like any other link, which means you can run OSPF or BGP over the tunnel later if you want to — a major advantage over policy-based VPNs. Remember that firewall policies still apply: you'll need explicit LOCAL_SUBNET → tunnel interface and tunnel interface → LOCAL_SUBNET policies, or traffic will be silently dropped even when the tunnel is up and green.

MikroTik as a Spoke

On the MikroTik side (RouterOS 7+), IPsec config is split across three sections: IP > IPsec > Profiles for Phase 1, IP > IPsec > Proposals for Phase 2, and IP > IPsec > Peers + Policies for the actual peer definition and traffic selectors. The peer points at your FortiGate WAN IP and references a profile. The policy is where you define your selectors — source is your MikroTik LAN subnet, destination is your FortiGate LAN subnet. And here is the number-one reason first-time IPsec configs silently fail: you must add a no-NAT masquerade rule for IPsec-bound traffic, placed above your general masquerade rule. Without it, packets get NATed before hitting the tunnel selector, the selector doesn't match, and the tunnel either won't form Phase 2 or will pass traffic that never arrives on the other side. No error, no warning — just silence.

Config: MikroTik Spoke to FortiGate Hub

javascript

# Phase 1 Profile
/ip ipsec profile
add name=forti-profile dh-group=modp2048 enc-algorithm=aes-256 \
    hash-algorithm=sha256 lifetime=1d nat-traversal=yes

# Phase 2 Proposal
/ip ipsec proposal
add name=forti-proposal auth-algorithms=sha256 \
    enc-algorithms=aes-256-cbc lifetime=1h pfs-group=none

# Peer — point at FortiGate WAN IP
/ip ipsec peer
add address=203.0.113.1/32 name=forti-hub \
    profile=forti-profile exchange-mode=ike2

# Traffic selector — LAN-to-LAN
/ip ipsec policy
add src-address=10.10.10.0/24 dst-address=10.20.20.0/24 \
    tunnel=yes action=encrypt peer=forti-hub proposal=forti-proposal

# No-NAT rule — MUST be above your masquerade rule
/ip firewall nat
add chain=srcnat src-address=10.10.10.0/24 dst-address=10.20.20.0/24 \
    action=accept comment="No NAT for IPsec traffic" place-before=0

Mirror these algorithm choices exactly on the FortiGate side — a single mismatch between Phase 1 or Phase 2 proposals causes negotiation to silently fail while both sides report "connecting."

Verifying the Tunnel

Once both sides are configured, check status on FortiGate under Monitor > IPsec Monitor — you want green on both Phase 1 and Phase 2. On MikroTik, run /ip ipsec active-peers print and /ip ipsec installed-sa print to confirm SAs are established and byte counters are incrementing as you ping across the tunnel. Phase 1 up but Phase 2 failing almost always means a proposal mismatch. Phase 1 failing is usually a PSK mismatch or an algorithm the remote doesn't support. If traffic isn't flowing even with both phases green, the no-NAT rule is missing or out of order — check /ip firewall nat print and make sure the accept rule appears before the masquerade rule.

Once it clicks, you'll never want to manage split networks again. Next step: run OSPF across the tunnel so your routes advertise themselves. But that's a story for another issue.


Until next week — keep the packets flowing.

Michael