# Managed deployment templates These files are administrator templates, not consumer-app features. Validate and sign edited profiles in the MDM product before deployment. Every example bundle ID, UUID, server, profile ID and credential must be replaced. ## Qeli per-app VPN `Qeli-PerApp-VPN.mobileconfig` uses Apple's `com.apple.vpn.managed.applayer` payload and the Qeli packet tunnel provider. Keep these identifiers aligned with `Config/Signing.xcconfig`: - `VPNSubType`: the containing Qeli app bundle ID (`QELI_APP_BUNDLE_ID`). - `VPN.ProviderBundleIdentifier`: `QELI_TUNNEL_BUNDLE_ID`. - `VPNUUID`: the stable UUID the MDM service also assigns to each managed app. - `VendorConfig.profileID`: a profile UUID already present in Qeli's encrypted App Group store. The example does not provision credentials or profile text. On iOS, the target app must itself be managed. Associate it with the VPN by setting the same `VPNUUID` in the managed app's attributes. For an MDM `InstallApplication` command, the relevant fragment is: ```xml Attributes VPNUUID 1653840A-E082-4CC2-877A-A8D188C183B6 ``` Declarative Device Management uses the equivalent `Attributes.VPNUUID` property on the managed app declaration. A normal App Store install can't assign arbitrary apps to this VPN and Qeli doesn't attempt to enumerate installed apps. Apple references: - https://developer.apple.com/documentation/devicemanagement/applayervpn - https://developer.apple.com/documentation/devicemanagement/installapplicationcommand/command-data.dictionary/attributes-data.dictionary ## Always On VPN `Apple-IKEv2-AlwaysOn.mobileconfig` documents Apple's actual Always On facility. It requires a supervised, MDM-managed device and an IKEv2 server. It does **not** make the Qeli custom Packet Tunnel Provider Always On and is not compatible with the Qeli wire protocol. For consumer devices use Qeli's VPN On Demand setting instead. The shared-secret placeholder keeps the example self-contained, but certificate authentication with a separately deployed identity payload is preferable in a real organization. Never deploy the placeholder secret or `.invalid` host names. Apple references: - https://support.apple.com/guide/deployment/depae3d361d0/web - https://developer.apple.com/documentation/devicemanagement/vpn - https://developer.apple.com/documentation/devicemanagement/vpn/alwayson-data.dictionary ## Managed app configuration `Qeli-Managed-App-Configuration.plist` is the dictionary to send as legacy managed app configuration, not a configuration profile. Qeli's standalone `ManagedConfigurationReader` reads it from `UserDefaults.standard["com.apple.configuration.managed"]` and accepts: - `configurationVersion` — integer schema version. - `activeProfileID` — UUID string referring to an existing encrypted profile. - `onDemandEnabled` — Boolean policy value. - `widgetControlsEnabled` — Boolean policy value. The reader itself is side-effect free. `AppModel` gives these managed values precedence at launch and whenever the app becomes active: it selects the managed profile for the next connection, enforces the managed On Demand value, and mirrors the widget-control policy into the App Group so the widget extension can reject disabled actions. An `activeProfileID` key that is malformed or does not match an encrypted local profile fails closed: Qeli blocks manual/widget starts, stops the old tunnel, removes On Demand rules and disables the stale provider configuration. It never accepts profile text, passwords, or private keys. On newer managed deployments, Apple's ManagedApp framework can replace this legacy `UserDefaults` delivery path. ### Bootstrap order (this one bites) The policy references a profile by UUID; it never carries the profile itself. So the profile has to exist on the device **before** the configuration arrives, and the order is not interchangeable: 1. Install Qeli as a **managed** app. Legacy managed app configuration is only delivered to apps the MDM installed — sideloaded or App Store copies never see the key. 2. Get the profile onto the device and note its UUID. Qeli accepts no profile text, password or key over MDM by design, so this step is a `qeli://` link, a QR scan or an INI import — done by the user or seeded alongside a Per-App VPN payload. 3. Only then push the configuration dictionary with `activeProfileID` set to that UUID. Pushing step 3 first is the common mistake, and it does not fail quietly: an `activeProfileID` that matches nothing is treated as a policy violation, not as "no policy". Qeli fails closed — manual and widget starts are blocked, a running tunnel is stopped, On Demand rules are removed and the stale provider configuration is disabled. That is deliberate (a managed device must not silently fall back to a user-chosen profile), but it means a mis-ordered rollout looks like a broken app. ### Rollback Remove the managed configuration — or just the `activeProfileID` key — and control returns to the user: the app goes back to the locally selected profile, and an On Demand value that came from policy reverts to the app's own setting. Removing the policy does **not** delete profiles, credentials or the provider configuration; it only stops enforcing them. To hand a device back permanently, remove the policy first and confirm the app connects on a local profile, then unmanage or remove the app. Doing it the other way round leaves the last enforced state in place with nothing left to lift it. Apple reference: - https://developer.apple.com/documentation/devicemanagement/configuring-managed-apps-and-extensions