Automatic VPN with iOS and iPadOS

One shortcoming of the native settings on the iPhone and the iPad is that you can’t easily set up on-demand or automatic VPNs. While there is no way to do it in the GUI, you can, however create a profile and install it with all the necessary information and logic.

Profiles are just XML documents saved with the .mobileconfig extension.

I am not going to give an exhaustive tutorial of profiles, rather a working example (the one I use). I have removed the actual data (user names, passwords, shared secrets); you substitute your values in the appropriate places. Change the UUIDs to any random UUID in the same format. For more information on the profile structure and what options you have, you can consult the Apple documentation.

You can use Apple Configurator 2 to build the initial profile. Create a new profile, then add a VPN Payload. Put in all the correct values that you want. You can load the profile you created in to your iPhone/iPad and test that the VPN will connect.

Unfortunately, the tool, does not let you set OnDemand rules. Once you’ve testing that your VPN settings work, you can edit the profile you created with your favorite text editor. It is an XML file. The key is to add the OnDemand rules. These will go inside the IPSec block. I dropped this block in right after the SharedSecret, and it works for me.

         <key>DisconnectOnIdle</key>
        <integer>0</integer>
        <key>OnDemandEnabled</key>
        <integer>1</integer>
        <key>OnDemandRules</key>
        <array>
        
          <dict>
          <key>InterfaceTypeMatch</key>
            <string>Wifi</string>
          <key>SSIDMatch</key>
            <array>
              <string>MyWifi SSID</string>
              <string>Another SSID</string>
            </array>
          <key>Action</key>
            <string>Disconnect</string>
          </dict>

          <!-- Always use VPN on cellular.  Change "Connect" to "Disconnect" if you don't want VPN with cellular -->

          <dict>
          <key>InterfaceTypeMatch</key>
            <string>Cellular</string>
          <key>Action</key>
            <string>Connect</string>
          </dict>
                    
          <!-- Use VPN on any other WiFi network -->
          
          <dict>
          <key>InterfaceTypeMatch</key>
            <string>Any</string>
          <key>Action</key>
            <string>Connect</string>
          </dict>
        </array>

This complete example is what I use to connect to the L2TP VPN on my Ubiquiti UDM Pro. You will want to edit the names of things to suit your own tastes.

<?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>IPSec</key>
      <dict>
        <key>AuthenticationMethod</key>
        <string>SharedSecret</string>
        <key>LocalIdentifierType</key>
        <string>KeyID</string>
        <key>SharedSecret</key>
        <data>
        Your-Shared-Secret-String
        </data>
        <key>DisconnectOnIdle</key>
        <integer>0</integer>
        <key>OnDemandEnabled</key>
        <integer>1</integer>
        <key>OnDemandRules</key>
        <array>
        
          <dict>
          <key>InterfaceTypeMatch</key>
            <string>Wifi</string>
          <key>SSIDMatch</key>
            <array>
              <string>MyWifi SSID</string>
              <string>Another SSID</string>
            </array>
          <key>Action</key>
            <string>Disconnect</string>
          </dict>

          <!-- Always use VPN on cellular.  Change "Connect" to "Disconnect" if you don't want VPN with cellular -->

          <dict>
          <key>InterfaceTypeMatch</key>
            <string>Cellular</string>
          <key>Action</key>
            <string>Connect</string>
          </dict>
                    
          <!-- Use VPN on any other WiFi network -->
          
          <dict>
          <key>InterfaceTypeMatch</key>
            <string>Any</string>
          <key>Action</key>
            <string>Connect</string>
          </dict>
        </array>
      </dict>
      <key>IPv4</key>
      <dict>
        <key>OverridePrimary</key>
        <integer>1</integer>
      </dict>
      <key>PPP</key>
      <dict>
        <key>AuthName</key>
        <string>vpn_user</string>
        <key>AuthPassword</key>
        <string>my_complex_password</string>
        <key>CommRemoteAddress</key>
        <string>vpnhost.server.com</string>
      </dict>
      <key>PayloadDescription</key>
      <string>Configures VPN settings</string>
      <key>PayloadDisplayName</key>
      <string>Home VPN (Cellular)</string>
      <key>PayloadIdentifier</key>
      <string>com.apple.vpn.managed.57624016-843E-4BDF-94F0-F501A2A21379</string>
      <key>PayloadType</key>
      <string>com.apple.vpn.managed</string>
      <key>PayloadUUID</key>
      <string>58654016-845E-4BAE-94FE-F603A2B21329</string>
      <key>PayloadVersion</key>
      <integer>1</integer>
      <key>Proxies</key>
      <dict>
	<key>ProxyAutoConfigURLString</key>
	<integer>0</integer>
				
	<key>HTTPEnable</key>
	<integer>1</integer>
        <key>HTTPPort</key>
        <integer>3128</integer>
        <key>HTTPProxy</key>
        <string>host.proxy.com</string>
        <key>HTTPSEnable</key>
	<integer>1</integer>
        <key>HTTPSPort</key>
        <integer>3128</integer>
        <key>HTTPSProxy</key>
        <string>host.proxy.com</string>
      </dict>
      <key>UserDefinedName</key>
      <string>Technomancer</string>
      <key>VPNType</key>
      <string>L2TP</string>
    </dict>
  </array>
  <key>PayloadDescription</key>
  <string>This is a VPN Profile to connect back home using L2TP (including Cellular).</string>
  <key>PayloadDisplayName</key>
  <string>Home VPN (Cellular)</string>
  <key>PayloadIdentifier</key>
  <string>MyVPN.CDF577B6-9D2A-421E-9B11-679EC9249325</string>
  <key>PayloadRemovalDisallowed</key>
  <false/>
  <key>PayloadType</key>
  <string>Configuration</string>
  <key>PayloadUUID</key>
  <string>D8C395A8-8270-4644-921B-E5E4D58A3C37</string>
  <key>PayloadVersion</key>
  <integer>1</integer>
</dict>
</plist>

Leave a Comment