Skip to main content

EdgeRouter Site Build Standard (IPsec IKEv2 + BGP to Cato)

Overview

ItemValue
Applies toUbiquiti EdgeRouter sites (EdgeOS 3.0.1): Gembrook, Cockatoo, Gembrook West, Mater Christi (Emerald deferred)
DesignRoute-based IPsec IKEv2 VTIs to Cato Melbourne (primary) and Sydney (secondary) PoPs, eBGP to Cato ASN 64515
StatusSettled 26 Oct 2026 — fleet standard, proven at four sites
OwnerMitch Fraser

This page is the build standard for connecting an EdgeRouter site to Cato. It records the settled design, the one-time strongSwan change the EdgeRouters need, the EdgeOS configuration template, the two-WAN-path variant, verification and recovery, and — because it cost a site outage — what not to do. Per-site values live on the site pages in this book.


Fleet standard (summary)

Cato side (site IPsec page)

  • Site type IPsec IKEv2. Connection type Responder Only (the ER initiates). Destination type IPv4 (Melbourne 113.30.140.95 primary, Sydney 202.75.244.10 secondary).
  • Authentication identifier = the Cato-generated FQDN shown on the site's IPsec page, <catoSiteId>.23991.catonetworks.com, on both tunnel rows. For a two-path site the WAN2 row uses <catoSiteId>.23991.2.catonetworks.com. (IPv4 = site WAN IP also works and is mandatory if Bidirectional is ever used.)
  • Init message parameters set explicitly: AES-CBC-256 / SHA-256 / PRF SHA-256 / DH14. Auth parameters AES-CBC-256 / SHA-256 / DH14. (Only matter for Bidirectional, harmless otherwise. "Automatic" makes the ER answer NO_PROPOSAL_CHOSEN.)
  • Private IPs per the schema (site even / Cato odd). One BGP neighbour per tunnel: Cato ASN 64515, Peer ASN 6500<site>, Hold 90 / Keepalive 30, Advertise All routes.
  • Last-mile bandwidth set to the real plan speeds; a fresh PSK per tunnel. Never paste a PSK into chat or a ticket — treat it as burned and regenerate.

EdgeOS side

  • One-time drop-in /etc/strongswan.d/zz-pbr-cato.conf with charon { ignore_acquire_ts = yes } (see root cause). Survives reboot, not firmware upgrade.
  • Standard route-based VTI peers keyed by PoP IP, connection-type initiate, authentication id @<fqdn> (the @ forces an FQDN identity), remote-id <PoP IP>, ikev2-reauth no.
  • VTIs vti<site>00 / vti<site>01, /31 addresses, MTU 1400, OSPF passive, MSS clamp 1350 on vti.
  • BGP: export only the site's own prefixes (secondary prepends ASN twice), import allowlist 10.41.0.0/16 le 24 + 10.254.254.0/24 le 32 with local-pref 200 (primary) / 100 (secondary), administrative distance 115, keepalive 30 / hold 90, soft-reconfiguration inbound.

Root cause: why ER-initiated tunnels would not re-establish on their own (proven 26 Oct 2026)

Symptom: a manual ipsec up always worked, but after any drop (or reboot) the tunnels never came back by themselves, with Cato in Responder Only mode. Cato logged nothing useful; the ER log showed Cato replying N(TS_UNACCEPT) to IKE_AUTH.

  • EdgeOS writes VTI peers to strongSwan as auto=route (a trap policy). Every automatic attempt is therefore acquire-triggered — by the BGP SYN or the UDP 10001 discovery broadcast heading into the VTI.
  • strongSwan prepends the triggering packet's selector to the traffic selectors of an acquire-triggered initiation, after the log line "proposing traffic selectors" (so the log misleadingly shows only 0.0.0.0/0). On the wire the automatic IKE_AUTH was 416 bytes versus 384 for a manual one: two extra 16-byte selectors, e.g. [10.254.6.60/32 tcp, 0.0.0.0/0] ⇔ [10.254.6.61/32 tcp/179, 0.0.0.0/0]. This is the documented charon.ignore_acquire_ts behaviour (default no; pfSense ships it as yes).
  • Cato's responder does not narrow per RFC 7296 §2.9 — it rejects any proposal carrying multiple traffic selectors. Cato KB "IPsec Tunnel Fails to Establish with TS_UNACCEPTABLE When Meraki VPN Health Check Is Enabled" states Cato "rejects the SA with a TS_UNACCEPTABLE notification when it receives multiple Traffic Selectors" and that Support can "apply a backend configuration". Cato's best practice note recommends "Initiate connection by Cato" for IKEv2 sites for this reason.
Confirmed by Cato Support (ticket reply 27 Oct 2026, Jerome Manalo): their review of the Gembrook primary-tunnel capture found the failed proposals carried TSi 10.254.6.60/32 (TCP flow) + 0.0.0.0/0 and TSr 10.254.6.61/32 tcp/179 + 0.0.0.0/0, "two entries within each traffic-selector payload, which Cato rejects with TS_UNACCEPTABLE"; Cato expects exactly one 0.0.0.0/0 pair per tunnel. The 05:30:05 UTC success they cite is the first unattended re-establish after the drop-in. Why the PA-440s never hit this: PAN-OS proposes only its configured proxy-ID (0/0 ⇔ 0/0). Eliminated by test: stale Cato state, simultaneous dual-PoP negotiation, crypto/DH choice, firewall/NAT, BGP configuration. The Cato per-site option "IKEv2 Send Single TS per payload" was tested and does not help — it governs how Cato encodes its own Network Ranges, not what it accepts. Fix: the ignore_acquire_ts = yes drop-in makes every ER attempt look exactly like a manual ipsec up. Proven at Gembrook 16:26: after ipsec down, the ER's own trap-triggered attempt sent a single-selector IKE_AUTH and established in about 1 second with Cato unable to initiate; both BGP neighbours returned unattended.

Alternative that also works: Bidirectional (fallback only)

Cato site Bidirectional, destination/identifier = the site WAN IPv4 on both rows, Init parameters explicit; ER peers connection-type respond with authentication id <WAN IP>. Cato then initiates every 60 s while down. EdgeOS still writes auto=route so the ER keeps trying in the background (harmless). Not the standard because Cato cannot initiate through NAT — which rules it out for every PTP/fibre path that NATs through a hub PA-440. Cockatoo was first built this way and has since been moved to the standard.


DO NOT DO: policy-based IPsec on an EdgeRouter (site outage, 26 Oct 2026 ~14:30)

The Cato AI assistant suggested removing vti bind and adding tunnel 1 local prefix 10.6.0.0/16 remote prefix 0.0.0.0/0 on both Cato peers ("Cato requires policy-based"). Committing it took Gembrook offline: the kernel IPsec policy diverted all traffic from 10.6.0.0/16 into the Cato tunnel — overriding routing, including inter-site traffic to the hub — and removed the VTIs the BGP sessions ran over. Recovered by rebooting onto the saved config.boot. Cato's own IKEv2 site documentation supports route-based 0/0 tunnels; policy-based is the Meraki-specific KB workaround and does not even fix the multi-TS issue. Never apply policy-based tunnels on any ER site.


Build recipe (single-WAN site)

  1. Audit the device: show version, show interfaces, show ip route, show ip ospf neighbor, show configuration commands | grep -E 'firewall|nat|vpn|ospf'. Note the WAN IP, LAN prefixes, loopback, hub VTIs, and that the WAN-local firewall already accepts IKE 500/4500 and ESP from any peer (all PBR ERs do, for the hub tunnels).
  2. Create the Cato site (IPsec IKEv2, Responder Only, FQDN identifiers, IPv4 PoP destinations, explicit parameters, private IPs per schema, BGP neighbours, real bandwidth) and generate PSKs.
  3. Apply the strongSwan drop-in (below). Hub tunnels bounce for about 2 seconds on ipsec restart.
  4. Apply the EdgeOS template with the site values. Set the VTI /31 addresses and commit before adding the BGP neighbours (the validator rejects a neighbour that is not inside a configured VTI subnet; a /30 typo will do the same).
  5. commit-confirm 10, verify, confirm, save.
  6. Run the unattended re-establish proof (below). Only after that is the site "done".

EdgeOS template

Replace <S> with the site number, <SITE> with the site name, <catoSiteId> from the Cato page, and the WAN / loopback / legacy-range values from the audit. Quote PSKs.

# ---- One-time, outside EdgeOS config (survives reboot, NOT firmware upgrade) ----
sudo tee /etc/strongswan.d/zz-pbr-cato.conf >/dev/null <<'EOF'
# PBR: suppress acquire-derived traffic selectors so trap-triggered IKEv2
# initiations propose only the configured 0.0.0.0/0 (Cato rejects multi-TS).
# Not preserved by EdgeOS firmware upgrade - re-apply after upgrading.
charon {
    ignore_acquire_ts = yes
}
EOF
sudo ipsec restart      # hub tunnels bounce ~2 s

# ---- EdgeOS configuration (replace <...> values; PSKs in single quotes) ----
configure

# IKE / ESP groups
set vpn ipsec ike-group IKE-CATO key-exchange ikev2
set vpn ipsec ike-group IKE-CATO ikev2-reauth no
set vpn ipsec ike-group IKE-CATO lifetime 19800
set vpn ipsec ike-group IKE-CATO proposal 1 dh-group 14
set vpn ipsec ike-group IKE-CATO proposal 1 encryption aes256
set vpn ipsec ike-group IKE-CATO proposal 1 hash sha256
set vpn ipsec ike-group IKE-CATO dead-peer-detection action restart
set vpn ipsec ike-group IKE-CATO dead-peer-detection interval 30
set vpn ipsec ike-group IKE-CATO dead-peer-detection timeout 30
set vpn ipsec esp-group ESP-CATO lifetime 3600
set vpn ipsec esp-group ESP-CATO mode tunnel
set vpn ipsec esp-group ESP-CATO pfs dh-group14
set vpn ipsec esp-group ESP-CATO proposal 1 encryption aes256
set vpn ipsec esp-group ESP-CATO proposal 1 hash sha256

# VTIs (site side even, Cato side odd; MUST be /31)
set interfaces vti vti<S>00 address 10.254.<S>.<S>0/31
set interfaces vti vti<S>00 description 'Cato Melbourne (primary)'
set interfaces vti vti<S>00 mtu 1400
set interfaces vti vti<S>01 address 10.254.<S>.<S>2/31
set interfaces vti vti<S>01 description 'Cato Sydney (secondary)'
set interfaces vti vti<S>01 mtu 1400
set protocols ospf passive-interface vti<S>00
set protocols ospf passive-interface vti<S>01
set firewall options mss-clamp interface-type vti
set firewall options mss-clamp mss 1350

# Peers (route-based VTI, ER initiates, FQDN identifier)
set vpn ipsec site-to-site peer 113.30.140.95 authentication mode pre-shared-secret
set vpn ipsec site-to-site peer 113.30.140.95 authentication pre-shared-secret '<PSK-PRIMARY>'
set vpn ipsec site-to-site peer 113.30.140.95 authentication id @<catoSiteId>.23991.catonetworks.com
set vpn ipsec site-to-site peer 113.30.140.95 authentication remote-id 113.30.140.95
set vpn ipsec site-to-site peer 113.30.140.95 connection-type initiate
set vpn ipsec site-to-site peer 113.30.140.95 description 'Cato Melbourne PoP'
set vpn ipsec site-to-site peer 113.30.140.95 ike-group IKE-CATO
set vpn ipsec site-to-site peer 113.30.140.95 local-address <WAN-IP-PRIMARY-PATH>
set vpn ipsec site-to-site peer 113.30.140.95 vti bind vti<S>00
set vpn ipsec site-to-site peer 113.30.140.95 vti esp-group ESP-CATO

set vpn ipsec site-to-site peer 202.75.244.10 authentication mode pre-shared-secret
set vpn ipsec site-to-site peer 202.75.244.10 authentication pre-shared-secret '<PSK-SECONDARY>'
set vpn ipsec site-to-site peer 202.75.244.10 authentication id @<catoSiteId>.23991.catonetworks.com
set vpn ipsec site-to-site peer 202.75.244.10 authentication remote-id 202.75.244.10
set vpn ipsec site-to-site peer 202.75.244.10 connection-type initiate
set vpn ipsec site-to-site peer 202.75.244.10 description 'Cato Sydney PoP'
set vpn ipsec site-to-site peer 202.75.244.10 ike-group IKE-CATO
set vpn ipsec site-to-site peer 202.75.244.10 local-address <WAN-IP-SECONDARY-PATH>
set vpn ipsec site-to-site peer 202.75.244.10 vti bind vti<S>01
set vpn ipsec site-to-site peer 202.75.244.10 vti esp-group ESP-CATO

# Routing policy
set policy prefix-list <SITE>-PREFIXES rule 10 action permit
set policy prefix-list <SITE>-PREFIXES rule 10 prefix 10.<S>.0.0/16
set policy prefix-list <SITE>-PREFIXES rule 10 le 24
set policy prefix-list <SITE>-PREFIXES rule 20 action permit
set policy prefix-list <SITE>-PREFIXES rule 20 prefix <legacy-range>/24
set policy prefix-list <SITE>-PREFIXES rule 90 action permit
set policy prefix-list <SITE>-PREFIXES rule 90 prefix <loopback>/32
set policy prefix-list CATO-ALLOWED-IN rule 10 action permit
set policy prefix-list CATO-ALLOWED-IN rule 10 prefix 10.41.0.0/16
set policy prefix-list CATO-ALLOWED-IN rule 10 le 24
set policy prefix-list CATO-ALLOWED-IN rule 20 action permit
set policy prefix-list CATO-ALLOWED-IN rule 20 prefix 10.254.254.0/24
set policy prefix-list CATO-ALLOWED-IN rule 20 le 32

set policy route-map CATO-CONNECTED rule 10 action permit
set policy route-map CATO-CONNECTED rule 10 match ip address prefix-list <SITE>-PREFIXES
set policy route-map CATO-OUT-PRI rule 10 action permit
set policy route-map CATO-OUT-PRI rule 10 match ip address prefix-list <SITE>-PREFIXES
set policy route-map CATO-OUT-SEC rule 10 action permit
set policy route-map CATO-OUT-SEC rule 10 match ip address prefix-list <SITE>-PREFIXES
set policy route-map CATO-OUT-SEC rule 10 set as-path-prepend '6500<S> 6500<S>'
set policy route-map CATO-IN-PRI rule 10 action permit
set policy route-map CATO-IN-PRI rule 10 match ip address prefix-list CATO-ALLOWED-IN
set policy route-map CATO-IN-PRI rule 10 set local-preference 200
set policy route-map CATO-IN-SEC rule 10 action permit
set policy route-map CATO-IN-SEC rule 10 match ip address prefix-list CATO-ALLOWED-IN
set policy route-map CATO-IN-SEC rule 10 set local-preference 100

# BGP
set protocols bgp 6500<S> parameters router-id <loopback>
set protocols bgp 6500<S> parameters distance prefix 0.0.0.0/0 distance 115
set protocols bgp 6500<S> redistribute connected route-map CATO-CONNECTED
set protocols bgp 6500<S> neighbor 10.254.<S>.<S>1 remote-as 64515
set protocols bgp 6500<S> neighbor 10.254.<S>.<S>1 description 'Cato Melbourne'
set protocols bgp 6500<S> neighbor 10.254.<S>.<S>1 timers holdtime 90
set protocols bgp 6500<S> neighbor 10.254.<S>.<S>1 timers keepalive 30
set protocols bgp 6500<S> neighbor 10.254.<S>.<S>1 soft-reconfiguration inbound
set protocols bgp 6500<S> neighbor 10.254.<S>.<S>1 route-map import CATO-IN-PRI
set protocols bgp 6500<S> neighbor 10.254.<S>.<S>1 route-map export CATO-OUT-PRI
set protocols bgp 6500<S> neighbor 10.254.<S>.<S>3 remote-as 64515
set protocols bgp 6500<S> neighbor 10.254.<S>.<S>3 description 'Cato Sydney'
set protocols bgp 6500<S> neighbor 10.254.<S>.<S>3 timers holdtime 90
set protocols bgp 6500<S> neighbor 10.254.<S>.<S>3 timers keepalive 30
set protocols bgp 6500<S> neighbor 10.254.<S>.<S>3 soft-reconfiguration inbound
set protocols bgp 6500<S> neighbor 10.254.<S>.<S>3 route-map import CATO-IN-SEC
set protocols bgp 6500<S> neighbor 10.254.<S>.<S>3 route-map export CATO-OUT-SEC

commit-confirm 10
# ... verify tunnels and BGP, then:
confirm
save

Verification

export VYATTA_PAGER=cat
show vpn ipsec status
show vpn ipsec sa                      # NOT 'show vpn ipsec state' - that prints live ESP keys
sudo ipsec statusall | grep -E 'peer-(113|202)'
show vpn log | grep -E 'peer-(113|202)' | grep -E 'initiating|IKE_AUTH response|CHILD_SA .* established|TS_UNACCEPT|AUTH_FAILED|NO_PROPOSAL'
show ip bgp summary
show ip bgp neighbors 10.254.<S>.<S>1 advertised-routes     # must be ONLY this site's prefixes
show ip bgp neighbors 10.254.<S>.<S>1 received-routes       # ~127 offered
show ip route bgp                                           # must be ONLY 10.41.0.0/16 + 10.254.254.x at [115/...]
show ip route | grep -E '10\.(1|3|4|5|6|7|8|9|10|11|12)\.'   # inter-site routes must still be OSPF [110/...] via hub VTIs
sudo ping -c 3 10.254.<S>.<S>1

Unattended re-establish proof

# Prove the ER re-establishes on its own (Cato is Responder Only, so it cannot help):
sudo ipsec down peer-113.30.140.95-tunnel-vti
# wait up to ~3 minutes, then:
show vpn log | grep peer-113.30.140.95 | grep -E 'initiating IKE_SA|sending packet.*4500|IKE_AUTH response|CHILD_SA .* established'
# Expect: 'initiating IKE_SA' (not 'typed'), IKE_AUTH request 384 bytes (FQDN id) or 352 (IPv4 id),
# response '[ IDr AUTH SA TSi TSr ]' and 'CHILD_SA ... established'. 416 bytes + N(TS_UNACCEPT) = drop-in missing.
show ip bgp summary

Two-WAN-path sites (one path per Cato HA role)

Sites with a PTP/fibre path through a hub plus an LTE path (Gembrook West, Mater Christi) use two tunnels, one per path: primary role = PTP/fibre path → Melbourne PoP, secondary role = LTE path → Sydney PoP. Both are in BGP; the primary carries local-pref 200 and no prepend, the secondary local-pref 100 with the ASN prepended twice, and Cato itself double-prepends secondary-role routes and only uses the secondary role when every primary-role tunnel is down. This is exactly the shape Cato's own HA guides use for third-party routers (FortiGate, Cisco IOS, VMware Edge).

Why not four tunnels (both PoPs over both paths) like the KL1 PA-440: EdgeOS keys site-to-site peer by address and has a single routing table, so two tunnels to the same PoP IP from two paths would need hostname-keyed peers (EdgeOS refuses them for VTIs: "an ip address must be specified for VTIs") plus a persistent ip rule post-config script. The only clean alternative is a distinct PoP address per path, and the account's three IPsec IP licences are all allocated. Rejected as too complex; revisit only if licences change.

Extra configuration for a two-path site:

  • Per-path host routes so each tunnel leaves by the right interface: set protocols static route 113.30.140.95/32 next-hop <PTP next hop> and set protocols static route 202.75.244.10/32 next-hop <LTE gateway>.
  • Peer local-address = the address on that path (the PTP side uses the private transit address; the hub PA-440 NATs it, so the tunnel runs NAT-T on UDP 4500 — the hub's NAT and security policy must permit 500/4500 from the transit subnet).
  • The LTE-local firewall ruleset on these sites is per-source, so add accept rules for the Sydney PoP (IKE 500/4500 and ESP). The PTP path enters an interface with no local ruleset.
  • Cato page: WAN2 row identifier <catoSiteId>.23991.2.catonetworks.com; last-mile for the PTP row is its share of the hub's link.
  • Do not export the transit /24 (e.g. 10.250.97.0/24, 192.168.127.0/24).

Operations

BGP neighbour reset (EdgeOS 3.0.1 has no working clear/reset command)

configure
set protocols bgp 6500<S> neighbor 10.254.<S>.<S>3 shutdown
commit
delete protocols bgp 6500<S> neighbor 10.254.<S>.<S>3 shutdown
commit
exit

Recovery after a bad commit

# From a hub-side box (or via the site loopback 10.100.x.1 / hub VTI address if LAN replies are being swallowed):
ssh <ER>
configure
load            # reloads the saved config.boot
commit
exit
# or, if the device is unreachable, power-cycle: it boots from config.boot (the last 'save').

EdgeOS 3.0.1 gotchas

  • Any set vpn ipsec commit — including logging changes — restarts charon: all tunnels on the box (hub ones included) bounce for about 2 seconds. Do IPsec commits in a quiet window.
  • sudo ipsec stroke loglevel net 1 / enc 1 give live detail but are lost on every charon restart. set vpn ipsec logging is persistent but noisy — remove it after the build.
  • show vpn ipsec state prints live ESP keys. Use show vpn ipsec sa. If keys were ever displayed or pasted, force a rekey.
  • VTI addresses must be /31. A /30 makes the BGP validator reject the neighbour.
  • parameters distance global ... is not accepted; use parameters distance prefix 0.0.0.0/0 distance 115. It applies to routes installed after the commit — reset the neighbour if the routes were already there.
  • Site-to-site peers are keyed by IP; hostname peers are refused for VTIs.
  • config.boot is in braces format — grep it by value, not by set-path. Commit "connecting to charon.ctl failed" on a logging change is the charon restart race and is harmless.
  • Use grep -E rather than match '\|'; sudo ping -c 3 rather than ping count; export VYATTA_PAGER=cat to stop the pager swallowing output.
  • If a bad firewall or IPsec policy swallows LAN replies, the device is usually still reachable on its loopback 10.100.x.1 or a hub VTI address.

Post-firmware-upgrade runbook

  1. Confirm /etc/strongswan.d/zz-pbr-cato.conf still exists; if not, re-create it and sudo ipsec restart.
  2. Run the unattended re-establish proof. A 416-byte IKE_AUTH followed by TS_UNACCEPT means the drop-in is missing.

Reference: Cato PoPs and schema

ItemValue
Melbourne PoP (primary)113.30.140.95
Sydney PoP (secondary)202.75.244.10
Cato ASN64515
Site ASN6500<site>
VTIsvti<site>00 (primary), vti<site>01 (secondary)
/31s10.254.<site>.<site>0/31 and .<site>2/31; site even, Cato odd
Identifier<catoSiteId>.23991.catonetworks.com (WAN2: .23991.2.)
Import allowlist10.41.0.0/16 le 24; 10.254.254.0/24 le 32
Known Cato site IDsGembrook 1000000006, Cockatoo 1000000007, Gembrook West 1000000008, Mater Christi 1000000009

Maintenance notes

Update this page if Cato support applies the backend multi-TS setting (the drop-in then becomes unnecessary but harmless), if PoP addresses or IP licences change, or after an EdgeOS firmware upgrade changes strongSwan behaviour. Keep the post-upgrade runbook in the fleet upgrade procedure.