If you followed the Build a Secure IKEv2 VPN Server on Linux guide, you have a working server. Now you need to connect your iPhone, iPad, or Mac to it — and if you’ve tried doing that through the Settings app alone, you’ve probably hit a wall. The UI exposes a fraction of what IKEv2 actually supports.
Apple devices support VPN configuration through .mobileconfig files — property list XML documents that define exactly how the connection should behave. These profiles give you access to cipher suite selection, Dead Peer Detection rates, MOBIKE, full-tunnel routing, and on-demand connection rules. None of that is accessible through the Settings UI. If you want a client that matches the security posture of your server, you need a profile.
This guide breaks down every relevant parameter so you can build a profile that actually fits your infrastructure — not just one that technically connects.
By the end of this guide, you’ll have:
- A complete, customizable
.mobileconfigprofile for IKEv2 - A clear understanding of what every parameter does and why it matters
- Practical on-demand rule patterns for different use cases
Prerequisites:
- A working IKEv2 VPN server (strongSwan or similar)
- Familiarity with XML structure — you don’t need to be fluent, just comfortable editing it
- Your server’s hostname and the authentication method it uses (EAP or certificate-based)
How Configuration Profiles Work
A .mobileconfig file is a property list (plist) XML document — the same format Apple uses internally for system configuration. When a user installs one of these profiles on their device, it doesn’t just set a preference. It tells the OS exactly how to manage the connection at a lower level than the UI ever exposes.
The outer container defines the profile itself. Inside it, a PayloadContent array holds one or more payload dictionaries, each configuring a different system feature. For VPN, you need exactly one payload of type com.apple.vpn.managed.
Here’s the skeleton:
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE plist PUBLIC '-//Apple//DTD PLIST 1.0//EN'
'http://www.apple.com/DTDs/PropertyList-1.0.dtd'>
<plist version='1.0'>
<dict>
<key>PayloadContent</key>
<array>
<!-- VPN payload goes here -->
</array>
<key>PayloadDisplayName</key>
<string>VPN Configuration Name</string>
<key>PayloadIdentifier</key>
<string>com.yourcompany.vpn.profile</string>
<key>PayloadType</key>
<string>Configuration</string>
<key>PayloadUUID</key>
<string>unique-uuid-here</string>
<key>PayloadVersion</key>
<integer>1</integer>
</dict>
</plist>What this does: The outer dict is the profile container. PayloadDisplayName is what shows up in Settings → General → VPN & Device Management. PayloadIdentifier should be a reverse-DNS style string unique to your organization and profile. PayloadUUID uniquely identifies this profile — generate a fresh UUID for each one. PayloadVersion stays at 1.
The real work happens inside PayloadContent.
The VPN Payload
The full IKEv2 VPN payload with all common parameters looks like this:
<dict>
<key>IKEv2</key>
<dict>
<key>AuthenticationMethod</key>
<string>None</string>
<key>RemoteAddress</key>
<string>vpn.example.com</string>
<key>RemoteIdentifier</key>
<string>vpn.example.com</string>
<key>ExtendedAuthEnabled</key>
<true/>
<key>IKESecurityAssociationParameters</key>
<dict>
<key>EncryptionAlgorithm</key>
<string>AES-256-GCM</string>
<key>IntegrityAlgorithm</key>
<string>SHA2-384</string>
<key>DiffieHellmanGroup</key>
<integer>20</integer>
<key>LifeTimeInMinutes</key>
<integer>1440</integer>
</dict>
<key>ChildSecurityAssociationParameters</key>
<dict>
<key>EncryptionAlgorithm</key>
<string>AES-256-GCM</string>
<key>IntegrityAlgorithm</key>
<string>SHA2-384</string>
<key>DiffieHellmanGroup</key>
<integer>20</integer>
<key>LifeTimeInMinutes</key>
<integer>1440</integer>
</dict>
<key>EnablePFS</key>
<true/>
<key>DeadPeerDetectionRate</key>
<string>Medium</string>
<key>DisableMOBIKE</key>
<integer>0</integer>
<key>DisableRedirect</key>
<integer>0</integer>
<key>EnableCertificateRevocationCheck</key>
<integer>0</integer>
<key>UseConfigurationAttributeInternalIPSubnet</key>
<integer>0</integer>
<key>OnDemandEnabled</key>
<integer>1</integer>
<key>OnDemandRules</key>
<array>
<dict>
<key>Action</key>
<string>Connect</string>
</dict>
</array>
</dict>
<key>IPv4</key>
<dict>
<key>OverridePrimary</key>
<integer>1</integer>
</dict>
<key>PayloadDescription</key>
<string>Configures VPN settings</string>
<key>PayloadDisplayName</key>
<string>vpn.example.com</string>
<key>PayloadIdentifier</key>
<string>com.apple.vpn.managed.unique-id</string>
<key>PayloadType</key>
<string>com.apple.vpn.managed</string>
<key>PayloadUUID</key>
<string>unique-uuid-here</string>
<key>PayloadVersion</key>
<integer>1</integer>
<key>Proxies</key>
<dict>
<key>HTTPEnable</key>
<integer>0</integer>
<key>HTTPSEnable</key>
<integer>0</integer>
</dict>
<key>UserDefinedName</key>
<string>My VPN Connection</string>
<key>VPNType</key>
<string>IKEv2</string>
</dict>That’s the complete payload. Now let’s go through each section so you know what you’re actually setting.
Connection Settings
RemoteAddress and RemoteIdentifier
<key>RemoteAddress</key>
<string>vpn.example.com</string>
<key>RemoteIdentifier</key>
<string>vpn.example.com</string>RemoteAddress is where your device connects — the hostname or IP of your VPN server. Use a DNS name rather than an IP address when possible; it gives you flexibility if the server ever moves.
RemoteIdentifier is the identity your server presents during IKE negotiation. In most setups, this matches the server’s certificate subject or Subject Alternative Name (SAN). It must align with what your server actually sends during the handshake — mismatches cause the connection to fail silently or with cryptic errors. If your server certificate is issued for vpn.example.com, that’s what goes here.
AuthenticationMethod and ExtendedAuthEnabled
<key>AuthenticationMethod</key>
<string>None</string>
<key>ExtendedAuthEnabled</key>
<true/>This pair controls how authentication works. Setting AuthenticationMethod to None means you’re not using certificate-based client authentication — instead, you’re relying on EAP (Extended Authentication Protocol), typically EAP-MSCHAPv2 for username and password.
When ExtendedAuthEnabled is true, the device will prompt for credentials on first connection, or use saved credentials from the Keychain. For certificate-based authentication, set AuthenticationMethod to Certificate and supply the certificate payload separately.
What this does: Think of Phase 1 (IKE) as proving the server is who it says it is, and EAP as proving you are who you say you are. These two fields configure the second part of that handshake.
Security Association Parameters
This is where the cryptographic work happens. IKEv2 has two phases, each with its own security association (SA):
- IKESecurityAssociationParameters — Phase 1, the IKE SA. This governs the control channel: the negotiation itself.
- ChildSecurityAssociationParameters — Phase 2, the Child SA. This governs the actual data traffic.
You can configure them independently, but in most cases you want the same settings for both. Here’s what each parameter controls:
EncryptionAlgorithm
<key>EncryptionAlgorithm</key>
<string>AES-256-GCM</string>Options: AES-256-GCM, AES-256, AES-128-GCM, AES-128, 3DES.
Use AES-256-GCM. It’s an Authenticated Encryption with Associated Data (AEAD) cipher — meaning it handles both confidentiality and integrity in a single operation, and it’s hardware-accelerated on every modern Apple device. 3DES is listed here only so you know to avoid it.
IntegrityAlgorithm
<key>IntegrityAlgorithm</key>
<string>SHA2-384</string>Options: SHA2-512, SHA2-384, SHA2-256, SHA1-96.
When using GCM encryption, the integrity algorithm provides additional assurance on top of what GCM already guarantees. SHA2-384 is a reasonable choice — stronger than 256-bit, more practical than 512-bit, and matches P-384 if you’re using ECC for your DH group. Avoid SHA1-96; SHA-1 is deprecated for good reason.
DiffieHellmanGroup
<key>DiffieHellmanGroup</key>
<integer>20</integer>This controls the key exchange group used during negotiation. Higher numbers mean stronger (and slower) key exchange:
14— 2048-bit MODP. Minimum acceptable; avoid for new deployments.19— P-256 (256-bit ECP)20— P-384 (384-bit ECP). Recommended.21— P-521 (521-bit ECP). Maximum, with diminishing returns in practice.
Group 20 (P-384) gives you excellent security with reasonable connection setup time. The ECP groups (19–21) use elliptic curve Diffie-Hellman rather than classic modular arithmetic — they’re stronger per bit and faster than equivalent MODP groups.
One important constraint: this setting must match what your server offers. If your strongSwan configuration doesn’t include ecp384 in its proposals, the negotiation will fail. Check your server’s ike= and esp= strings before deploying the profile.
LifeTimeInMinutes
<key>LifeTimeInMinutes</key>
<integer>1440</integer>How long each security association remains valid before rekeying. 1440 minutes is 24 hours — a common default. Shorter lifetimes mean more frequent rekeying, which slightly limits the exposure window if a session key is ever compromised. The trade-off is connection overhead and battery impact on mobile devices. For most deployments, 24 hours is fine.
Connection Behavior
EnablePFS
<key>EnablePFS</key>
<true/>Perfect Forward Secrecy. When enabled, each session uses a fresh set of ephemeral keys derived from a new Diffie-Hellman exchange, independent of the long-term server key. If your server’s private key is ever compromised, past session traffic remains protected.
Always enable this. There’s no meaningful downside.
DeadPeerDetectionRate
<key>DeadPeerDetectionRate</key>
<string>Medium</string>Dead Peer Detection (DPD) is how IKEv2 confirms the remote endpoint is still alive. Options are None, Low, Medium, and High. Medium sends periodic keepalives at a balanced interval — fast enough to detect failures within a reasonable window, not so frequent that it kills your battery.
Higher rates are useful if you frequently switch networks and need the tunnel to recover quickly. Lower rates make more sense on always-on fixed connections.
DisableMOBIKE
<key>DisableMOBIKE</key>
<integer>0</integer>MOBIKE — defined in RFC 4555 — is an IKEv2 extension that allows the connection to survive IP address changes without tearing down and renegotiating the tunnel. On a phone that constantly moves between LTE and Wi-Fi, this is what keeps the VPN connected through those transitions.
Set to 0 (enabled) unless your server doesn’t support it or you’re dealing with a specific compatibility issue. Disabling it on mobile devices will cause the tunnel to drop every time you switch networks.
DisableRedirect
<key>DisableRedirect</key>
<integer>0</integer>IKEv2 supports server-initiated redirects — useful in load-balanced or high-availability VPN setups where an initial endpoint can redirect clients to a less-loaded server. Leaving this at 0 (redirects enabled) is correct for most deployments.
Traffic Routing
OverridePrimary (Full Tunnel vs. Split Tunnel)
<key>IPv4</key>
<dict>
<key>OverridePrimary</key>
<integer>1</integer>
</dict>This is one of the most consequential settings in the profile. OverridePrimary set to 1 means full tunnel mode — all traffic, regardless of destination, goes through the VPN. The device’s default gateway is replaced with the VPN gateway.
Set to 0 for split tunnel, where only traffic destined for the VPN server’s network uses the tunnel, and everything else goes direct. Split tunnel is convenient but means your device’s regular internet traffic leaves unprotected. If you’re running a privacy or security-focused VPN, full tunnel is the right choice.
On-Demand Rules
On-demand rules are where configuration profiles earn their keep. The Settings UI has no equivalent. These rules let iOS and macOS decide when to connect, disconnect, or conditionally evaluate the VPN — automatically, without user intervention.
Rules are evaluated in order. The first matching rule wins.
Always Connect
<key>OnDemandEnabled</key>
<integer>1</integer>
<key>OnDemandRules</key>
<array>
<dict>
<key>Action</key>
<string>Connect</string>
</dict>
</array>What this does: The VPN connects automatically whenever the device has any network connectivity. No exceptions. This is the simplest rule set — one rule that always fires.
Connect Everywhere Except Trusted Networks
<key>OnDemandRules</key>
<array>
<dict>
<key>InterfaceTypeMatch</key>
<string>WiFi</string>
<key>SSIDMatch</key>
<array>
<string>HomeNetwork</string>
<string>TrustedOffice</string>
</array>
<key>Action</key>
<string>Disconnect</string>
</dict>
<dict>
<key>Action</key>
<string>Connect</string>
</dict>
</array>What this does: The first rule matches when the device is on Wi-Fi and the SSID is in the trusted list — and disconnects (or stays disconnected). The second rule is the catch-all that connects everywhere else. The result: VPN off at home and the office, on everywhere else.
This is the most practical rule set for personal use. The SSID matching is exact string comparison, so make sure the names match precisely.
Connect Only When Accessing Internal Resources
<key>OnDemandRules</key>
<array>
<dict>
<key>Action</key>
<string>EvaluateConnection</string>
<key>ActionParameters</key>
<array>
<dict>
<key>Domains</key>
<array>
<string>internal.company.com</string>
</array>
<key>DomainAction</key>
<string>ConnectIfNeeded</string>
</dict>
</array>
</dict>
</array>What this does: The VPN only connects when the device tries to reach a domain in the list. For everything else, traffic goes direct. This is split-tunnel on-demand — useful for accessing internal services without routing all traffic through the VPN. The trade-off is that regular internet traffic isn’t protected.
Installing the Profile
iOS and iPadOS
Transfer the .mobileconfig file to the device via AirDrop, email, or a web server. The device will show a “Profile Downloaded” notification. Go to Settings → General → VPN & Device Management, tap the downloaded profile, tap Install, and confirm. The device will show you exactly what the profile configures before you commit.
macOS
Double-click the .mobileconfig file. System Settings will open to the Profiles pane. Review the contents and click Install. You may be prompted for administrator credentials.
For MDM deployments, profiles can be pushed silently without user interaction. For personal use, the manual install flow is straightforward.
Generating UUIDs
Every profile and every payload needs a unique UUID. You’ll need at least two for a single-payload VPN profile. Generate them with:
uuidgenOr in Python:
import uuid
print(uuid.uuid4())Run it twice — once for the outer profile UUID, once for the VPN payload UUID. If you’re deploying profiles to multiple devices, each device gets the same profile with the same UUIDs. The UUIDs identify the profile structure, not a specific device installation.
Complete Template
Here’s the full, ready-to-customize profile. Replace all values in angle brackets:
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE plist PUBLIC '-//Apple//DTD PLIST 1.0//EN'
'http://www.apple.com/DTDs/PropertyList-1.0.dtd'>
<plist version='1.0'>
<dict>
<key>PayloadContent</key>
<array>
<dict>
<key>IKEv2</key>
<dict>
<key>AuthenticationMethod</key>
<string>None</string>
<key>ChildSecurityAssociationParameters</key>
<dict>
<key>EncryptionAlgorithm</key>
<string>AES-256-GCM</string>
<key>IntegrityAlgorithm</key>
<string>SHA2-384</string>
<key>DiffieHellmanGroup</key>
<integer>20</integer>
<key>LifeTimeInMinutes</key>
<integer>1440</integer>
</dict>
<key>DeadPeerDetectionRate</key>
<string>Medium</string>
<key>DisableMOBIKE</key>
<integer>0</integer>
<key>DisableRedirect</key>
<integer>0</integer>
<key>EnableCertificateRevocationCheck</key>
<integer>0</integer>
<key>EnablePFS</key>
<true/>
<key>ExtendedAuthEnabled</key>
<true/>
<key>IKESecurityAssociationParameters</key>
<dict>
<key>EncryptionAlgorithm</key>
<string>AES-256-GCM</string>
<key>IntegrityAlgorithm</key>
<string>SHA2-384</string>
<key>DiffieHellmanGroup</key>
<integer>20</integer>
<key>LifeTimeInMinutes</key>
<integer>1440</integer>
</dict>
<key>OnDemandEnabled</key>
<integer>1</integer>
<key>OnDemandRules</key>
<array>
<dict>
<key>Action</key>
<string>Connect</string>
</dict>
</array>
<key>RemoteAddress</key>
<string><YOUR_VPN_SERVER></string>
<key>RemoteIdentifier</key>
<string><YOUR_VPN_SERVER></string>
<key>UseConfigurationAttributeInternalIPSubnet</key>
<integer>0</integer>
</dict>
<key>IPv4</key>
<dict>
<key>OverridePrimary</key>
<integer>1</integer>
</dict>
<key>PayloadDescription</key>
<string>Configures VPN settings</string>
<key>PayloadDisplayName</key>
<string><YOUR_VPN_SERVER></string>
<key>PayloadIdentifier</key>
<string>com.apple.vpn.managed.<UNIQUE_ID></string>
<key>PayloadType</key>
<string>com.apple.vpn.managed</string>
<key>PayloadUUID</key>
<string><GENERATE_UUID></string>
<key>PayloadVersion</key>
<integer>1</integer>
<key>Proxies</key>
<dict>
<key>HTTPEnable</key>
<integer>0</integer>
<key>HTTPSEnable</key>
<integer>0</integer>
</dict>
<key>UserDefinedName</key>
<string><FRIENDLY_NAME></string>
<key>VPNType</key>
<string>IKEv2</string>
</dict>
</array>
<key>PayloadDisplayName</key>
<string>IKEv2 VPN <YOUR_VPN_SERVER></string>
<key>PayloadIdentifier</key>
<string><GENERATE_UUID></string>
<key>PayloadRemovalDisallowed</key>
<false/>
<key>PayloadType</key>
<string>Configuration</string>
<key>PayloadUUID</key>
<string><GENERATE_UUID></string>
<key>PayloadVersion</key>
<integer>1</integer>
</dict>
</plist>A Note on Cipher Suite Alignment
The profile parameters are only half the equation. They must match what your server actually proposes. If you configure AES-256-GCM with Group 20 in the profile but your strongSwan server doesn’t include those in its ike= and esp= proposals, the handshake will fail — usually with a generic “couldn’t connect” error that doesn’t tell you why.
Before deploying a profile, verify your server’s configuration accepts the same algorithms. On a strongSwan server, your /etc/ipsec.conf (or swanctl equivalent) should include proposals that explicitly list the cipher suites you want to use. The server and client need to find common ground — the profile declares what the client is willing to use, the server declares what it’s willing to use, and they negotiate from the intersection.
If you’re building the server side, the Build a Secure IKEv2 VPN Server on Linux guide covers the server configuration that pairs with this profile.
Footnotes
[1] Apple Configuration Profile Reference — VPN payload: https://developer.apple.com/documentation/devicemanagement/vpn
[2] IKEv2 Cipher Suite Reference (strongSwan wiki): https://wiki.strongswan.org/projects/strongswan/wiki/IKEv2CipherSuites
[3] RFC 4555 — IKEv2 Mobility and Multihoming Protocol (MOBIKE): https://www.rfc-editor.org/rfc/rfc4555
[4] Apple Enterprise Deployment Documentation: https://support.apple.com/guide/deployment/
Tags: VPN, IKEv2, Apple, iOS, macOS, Security, Self-Hosting, Networking