Site-to-Site IKEv2 VPN: Connecting UniFi to a Linux strongSwan Server

Site-to-Site IKEv2 VPN: Connecting UniFi to a Linux strongSwan Server
Photo by Jake / Unsplash

Introduction

The previous guide on this site covers building a strongSwan IKEv2 VPN server that individual devices can connect to — your phone, laptop, or any client that supports IKEv2. That's a roadwarrior setup, and it works well for what it is.

This guide solves a different problem. If you have a second location — a home office, a remote cabin, a family member's house — and you want the networks at both sites to talk to each other, you need a site-to-site VPN. Every device on the remote network reaches every device on the home network as if they were on the same LAN, without installing VPN software on each one.

If your remote location runs UniFi gear, getting it to speak IKEv2 with a Linux strongSwan server takes some specific configuration on both ends. UniFi's site-to-site IKEv2 support uses pre-shared key (PSK) authentication rather than certificates and EAP like the roadwarrior setup does, which means a separate connection block and a bit of care about how strongSwan handles the two modes simultaneously.

By the end of this guide, you'll have:

  • A named site-to-site connection in strongSwan using IKEv2 and PSK
  • The correct cipher suite to match UniFi's requirements (AES-256, SHA-256, DH Group 14)
  • Dead Peer Detection configured to automatically re-establish the tunnel if it drops
  • The matching UniFi Network configuration to complete the connection

Prerequisites:

  • A working strongSwan IKEv2 server (see Build a Secure IKEv2 VPN Server on Linux)
  • A UniFi router (UDM, UDM Pro, UDM SE, or USG) with admin access to the Network app
  • Root access to the Linux server running strongSwan
  • The public IP or hostname of both endpoints
  • Basic comfort with the Linux command line

Architecture Overview

Before touching any config files, it helps to understand what's actually happening.

In a roadwarrior VPN, the server sits at a known address and clients dial in from wherever they are. The server doesn't need to know the client's IP in advance. In a site-to-site VPN, you have two fixed networks — each with a router — and you're creating a permanent encrypted tunnel between them. Traffic destined for the remote subnet gets routed through the tunnel automatically, without any action from the end devices.

For our purposes:

  1. Left side — your Linux strongSwan server, protecting subnet 10.1.10.0/24
  2. Right side — your UniFi router, protecting subnet 10.2.40.0/24
  3. Authentication — a pre-shared key (PSK) that both sides agree on before the tunnel comes up
  4. IKE Phase 1 — negotiates the secure channel: AES-256, SHA-256, DH Group 14 (modp2048)
  5. IKE Phase 2 — negotiates the traffic encryption: AES-256, SHA-256

The subnets in this guide (10.1.10.0/24 and 10.2.40.0/24) are examples. Use whatever RFC 1918 ranges your networks actually run. They must not overlap, or routing breaks in interesting and confusing ways.


Step 1: Add the Site-to-Site Connection to ipsec.conf

Open /etc/ipsec.conf on your Linux server:

sudo nano /etc/ipsec.conf

Add the following block below your existing roadwarrior connection (or at the end of the file, after the config setup and any existing conn blocks):

conn site-to-site
    auto=add
    left=%any
    leftid=@vpnserver
    leftsubnet=10.1.10.0/24
    right=YOUR_UNIFI_PUBLIC_IP
    rightid=@unifi
    rightsubnet=10.2.40.0/24
    ike=aes256-sha256-modp2048
    esp=aes256-sha256
    keyexchange=ikev2
    authby=psk
    dpdaction=restart
    keyingtries=%forever

Replace YOUR_UNIFI_PUBLIC_IP with the actual public IPv4 or IPv6 address of your UniFi router's WAN interface, and replace the subnets with your actual networks.

What each setting does:

  • auto=add — Load this connection at startup, but don't initiate it. Let the UniFi router initiate, since it knows when it's ready. If you want strongSwan to initiate, use auto=start instead.
  • left=%any — Accept connections from any source IP. Since your UniFi's WAN IP may change, this is more resilient than pinning to a specific address.
  • leftid=@vpnserver — The identifier your server presents to the remote peer. The @ prefix marks this as a fully qualified domain name (FQDN) identifier. This must match what you configure as the "Remote ID" on the UniFi side.
  • leftsubnet=10.1.10.0/24 — The subnet on the server side that should be reachable through the tunnel.
  • right=YOUR_UNIFI_PUBLIC_IP — The IP address strongSwan expects the remote peer to connect from. If your UniFi has a dynamic WAN IP, using %any here and relying on rightid for identification works, but is less precise.
  • rightid=@unifi — The identifier you expect the UniFi router to present. This must match what UniFi sends as its "Local ID," which is configurable in the Network app.
  • rightsubnet=10.2.40.0/24 — The subnet on the UniFi side that should be reachable through the tunnel.
  • ike=aes256-sha256-modp2048 — Phase 1 cipher suite. AES-256 for encryption, SHA-256 for integrity, and modp2048 (DH Group 14) for key exchange. This matches UniFi's site-to-site IKEv2 defaults.
  • esp=aes256-sha256 — Phase 2 cipher suite for the actual traffic encryption.
  • keyexchange=ikev2 — Explicitly use IKEv2, not IKEv1.
  • authby=psk — Authenticate using a pre-shared key. This is different from the certificate + EAP method used in the roadwarrior config.
  • dpdaction=restart — Dead Peer Detection. If the tunnel goes quiet, strongSwan will attempt to restart it automatically. For a permanent site-to-site link, this is what you want.
  • keyingtries=%forever — Keep retrying indefinitely if the connection fails to establish. Combined with dpdaction=restart, this means the tunnel will recover from temporary outages without manual intervention.

Step 2: Add the Pre-Shared Key to ipsec.secrets

The PSK lives in /etc/ipsec.secrets. Open it:

sudo nano /etc/ipsec.secrets

Add a line for the site-to-site connection, using the same identifiers from the connection block:

@vpnserver @unifi : PSK "replace-this-with-a-strong-random-key"

What this does: This line tells strongSwan that when a connection is negotiated between the identity @vpnserver (your server) and @unifi (the UniFi router), it should use this pre-shared key for authentication. The PSK must be identical on both sides — strongSwan and the UniFi router — or the IKE handshake will fail.

Generate a strong key:

openssl rand -base64 32

Copy the output. You'll need it again when configuring the UniFi side.

A note on keeping secrets. The /etc/ipsec.secrets file should be readable only by root. Verify its permissions:

ls -la /etc/ipsec.secrets

You want -rw------- 1 root root. If it's more permissive than that:

sudo chmod 600 /etc/ipsec.secrets

Step 3: Reload strongSwan

With both files updated, reload the configuration without dropping existing connections:

sudo ipsec reload

Then load the new connection specifically:

sudo ipsec up site-to-site

strongSwan will attempt to bring up the tunnel if auto=start was set, or wait for the UniFi to initiate if auto=add was used. Check the status:

sudo ipsec status

You should see site-to-site listed. If the UniFi side isn't configured yet, you'll see it as CONNECTING or simply loaded but not established — that's expected.


Step 4: Configure the UniFi Network App

Log into your UniFi Network application and navigate to Settings → VPN → Site-to-Site VPN. Create a new VPN with the following values. The exact field labels may vary slightly depending on your firmware version, but the mapping is consistent:

Connection type: IPsec / IKEv2

Local WAN: The WAN interface your UniFi router uses for this tunnel

Remote IP (Server IP): Your Linux server's public IP or domain name

Local Network: 10.2.40.0/24 (the subnet behind the UniFi — your rightsubnet from Step 1)

Remote Network: 10.1.10.0/24 (the subnet behind the strongSwan server — your leftsubnet from Step 1)

Pre-Shared Key: The exact same key you put in /etc/ipsec.secrets

Local ID: unifi (without the @ — UniFi adds the FQDN prefix internally; this must match your rightid=@unifi)

Remote ID: vpnserver (again without the @; must match your leftid=@vpnserver)

IKE Encryption: AES-256

IKE Hash: SHA-256

IKE DH Group: 14 (2048-bit MODP)

IPsec Encryption: AES-256

IPsec Hash: SHA-256

IPsec PFS Group: 14 (if available; some firmware versions call this "Perfect Forward Secrecy Group")

Save the configuration. The UniFi router will attempt to initiate the tunnel immediately.


Step 5: Verify the Tunnel

Back on the Linux server, check whether the tunnel came up:

sudo ipsec statusall

A healthy tunnel will show the connection as ESTABLISHED with the negotiated cipher suites and the traffic selectors (the subnets) for both sides. You'll also see Security Associations (SAs) listed under the connection.

Test reachability from the server side by pinging a device on the UniFi network:

ping 10.2.40.1

And from a device on the UniFi network, try to reach something on 10.1.10.0/24. If pings go through in both directions, the tunnel is working.

If pings reach the UniFi gateway but not devices behind it, check that your UniFi's routing is configured to send 10.1.10.0/24 traffic through the VPN interface rather than out to the internet.


Troubleshooting

The tunnel shows CONNECTING but never ESTABLISHED. The most common cause is a mismatched PSK or mismatched IDs. The leftid/rightid values in ipsec.conf must exactly match what each side is sending. Check with:

sudo ipsec statusall | grep -A5 site-to-site

Enable more verbose logging temporarily:

sudo ipsec stroke loglevel ike 4

Then watch the logs:

sudo journalctl -fu strongswan

Look for messages about authentication failures or proposal mismatches — strongSwan is fairly specific about what went wrong.

Proposal mismatch errors. If you see no proposal chosen in the logs, the cipher suites on one side don't match the other. Double-check that both sides are using AES-256, SHA-256, and DH Group 14 for both IKE and ESP phases. UniFi sometimes defaults to different groups depending on firmware; confirm in the UniFi UI that Group 14 is selected explicitly.

The tunnel comes up but traffic doesn't flow. This is usually a routing or firewall issue, not a VPN issue. On the Linux server, confirm that routes are in place:

ip route show

Also verify that UFW isn't blocking forwarded traffic between the two subnets. The firewall setup in the IKEv2 server guide covers the forwarding rules — those same rules apply here.

The tunnel drops periodically and doesn't recover. If Dead Peer Detection isn't restarting the tunnel as expected, verify dpdaction=restart is present in the connection block and that keyingtries=%forever is set. UniFi site-to-site connections generally have DPD enabled by default, but confirm this in the Network app if you're seeing regular drops.


Closing Thoughts

The roadwarrior and site-to-site configurations can coexist in the same ipsec.conf without conflict — strongSwan distinguishes them by connection name and the specifics of each conn block. You can have clients dialing in from their phones while two networks maintain a permanent tunnel, all through the same strongSwan instance.

The PSK approach used here is simpler to configure than certificate-based mutual authentication, but it does mean that anyone who obtains the shared key can impersonate either peer. Keep it out of version control and regenerate it if you suspect it's been exposed. For environments where that risk is unacceptable, strongSwan supports certificate-based authentication for site-to-site connections as well, though UniFi's support for that path is more limited.