monotux.tech

Auto toggle VPN on Apple devices

networking, apple, iOS, macOS, WireGuard

I run a few Apple devices at home (including the Macbook Air I’m typing this on), and I want them all to automagically connect to my VPN when I leave my house – and it turns out it’s pretty easy to set this up!

Below is based upon this gist, thank you deg0nz!

iOS #

There are two common methods to do this – either using the on-demand feature in the Wireguard app, or using the builtin mobileconf functionality. I went with the latter, which also works with other VPN technologies as well.

All you need is a working WireGuard configuration, a XML file and AirDrop to copy the XML to your mobile device. And the WireGuard app installed, of course!

An example configuration looks like this – make sure you replace UUIDs (mostly due to reasons), WireGuard config, WiFi networks and descriptions.

<?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>UserDefinedName</key>
        <!-- This is shown in Settings -> VPN -->
        <string>wireguard-on-demand</string>

        <key>PayloadDisplayName</key>
        <!-- This is shown in Settings -> General -> Profile -> [Profile Name] -> More Details -> VPN Settings -->
        <string>WireGuard on-demand</string>

        <key>PayloadIdentifier</key>
        <string>wtf.beh.vpn.wifi.untrusted</string>

        <key>PayloadUUID</key>
        <string>2EF2C036-516D-4E7F-8700-92EBF27C87A9</string>

        <key>VPNType</key>
        <string>VPN</string>

        <key>VPNSubType</key>
        <string>com.wireguard.ios</string>

        <key>VendorConfig</key>
        <dict>
          <key>WgQuickConfig</key>
          <string>
          [Interface]
          PrivateKey = <private wg key goes here>
          Address = 192.168.5.2/32
          DNS = 192.168.5.1

          [Peer]
          PublicKey = <server public key goes here>
          AllowedIPs = 192.168.5.0/24
          Endpoint = <vpn endpoint goes here>
          </string>
        </dict>

        <!-- Adjust your VPN server below -->
        <key>VPN</key>
        <dict>
           <key>RemoteAddress</key>
           <!-- vpn endpoint goes here, again! -->
           <string>vpn.example.com:1234</string>
           <key>AuthenticationMethod</key>
           <string>Password</string>
        </dict>

        <key>OnDemandEnabled</key>
        <integer>1</integer>

        <key>OnDemandRules</key>
        <array>

          <!-- Disconnect VPN for trusted WiFi networks -->
          <dict>
            <key>InterfaceTypeMatch</key>
            <string>WiFi</string>
            <key>SSIDMatch</key>
            <array>
              <!-- Add your trusted WiFi SSIDs below -->
              <string>Trusted SSID 1</string>
              <!-- <string>Trusted SSID 2...and as many as you'd like</string> -->
            </array>
            <key>Action</key>
            <string>Disconnect</string>
          </dict>

          <!-- VPN state for all other WiFi networks -->
          <dict>
            <key>InterfaceTypeMatch</key>
            <string>WiFi</string>
            <key>Action</key>
            <string>Connect</string>
          </dict>

          <!-- VPN default state, matches when connected via cellular -->
          <dict>
            <key>Action</key>
            <string>Connect</string>
          </dict>
        </array>

        <key>PayloadType</key>
        <string>com.apple.vpn.managed</string>
        <key>PayloadVersion</key>
        <integer>1</integer>
      </dict>

    </array>

    <key>PayloadDisplayName</key>
    <string>WireGuard unicorn non-home</string> <!-- This is the profile name -->
    <key>PayloadIdentifier</key>
    <string>wtf.beh.vpn.wifi.config.BAC9A693-7448-42AD-8B91-53745C3BF1D3</string>
    <key>PayloadRemovalDisallowed</key>
    <false />
    <key>PayloadType</key>
    <string>Configuration</string>
    <key>PayloadUUID</key>
    <string>72B898FE-EFAB-43B8-8726-1DD0A2CF951D</string>
    <key>PayloadVersion</key>
    <integer>1</integer>
  </dict>
</plist>

Save the above with file ending .mobileconfig, and use AirDrop (or whathaveyou) to send to your iOS device. Follow the on-screen instructions.

macOS #

For macOS I went with the GUI method to configure my on-demand VPN. I just created a new, empty VPN tunnel in the WireGuard app, and selected on-demand and excluded my ’trusted’ WiFi from the list. So now my laptop connects to my VPN anytime I’m not home, and disconnects the VPN when I’m home again.

Example setup, and no, that isn't my real private key...