Zion Boggan
repos/Mullvad iOS Killswitch
zionboggan.com ↗

Mullvad iOS Killswitch

Generate iOS .mobileconfig configuration profiles from WireGuard .conf files with a true kill switch and OnDemand auto-connect baked in.

1 commits First commit May 4, 2026 Last commit May 4, 2026 (1 month ago)
Python 69.3%Markdown 30.7%
Files 4 entries
README.md

mullvad-ios-killswitch

Generate iOS .mobileconfig configuration profiles from WireGuard .conf files with a true kill switch and OnDemand auto-connect baked in.

Why this exists

The WireGuard iOS app's UI does not expose:

  • IncludeAllNetworks (the toggle that makes the tunnel claim the entire default route at the iOS Network Extension level, so traffic outside the tunnel is blocked when the tunnel is down).
  • OnDemandEnabled with an unconditional Connect rule (the toggle that makes iOS auto-establish the tunnel any time the device has a network).

Both are gated behind Apple's MDM / configuration-profile path. Once you install a .mobileconfig that turns those keys on, the WireGuard app picks up the profile as a managed tunnel and the kill switch is enforced by iOS, not by the app. If the tunnel drops, the device does not fall back to the bare LTE / Wi-Fi route - traffic stops until the tunnel comes back.

This script takes a regular WireGuard .conf you already have (downloaded from Mullvad, your own server, anywhere) and wraps it in a properly signed- shaped .mobileconfig with those keys flipped on.

Install

No dependencies beyond Python 3.8+. Drop the script anywhere on your PATH.

Usage

Single config:

python gen_mobileconfig.py \
  my-tunnel.conf my-tunnel.mobileconfig \
  --name "Mullvad Atlanta (iPhone)" \
  --org "Personal Setup"

Batch a folder of configs (one .mobileconfig per .conf):

python gen_mobileconfig.py --batch ./wg-configs ./mobileconfigs

AirDrop or email the resulting .mobileconfig to the iOS device. Open the file from the Files / Mail / Messages app, accept the profile prompt in Settings, then open the WireGuard app once and confirm the tunnel is present and toggled on.

Verification

After installing on iOS:

  1. Open WireGuard, confirm the tunnel is on.
  2. Settings -> General -> VPN & Device Management -> tap the profile, confirm "Connect On Demand" is on.
  3. Toggle WireGuard off for a moment in the app. Try to load any page. It should fail. Toggle back on, traffic resumes.

If step 3 still loads pages while the tunnel is off, the kill switch is not active and the profile did not install correctly.

What the script does NOT do

  • Generate your WireGuard keys. Bring your own .conf.
  • Sign the .mobileconfig with an Apple developer certificate. iOS will warn that the profile is unsigned. That is fine for personal use - you install it manually. For a fleet deployment you should sign with openssl smime or push it through MDM.
  • Validate the upstream .conf. If the file does not have an Endpoint line, the script writes an empty RemoteAddress (iOS will tolerate this because WgQuickConfig carries the real endpoint, but it is uglier in the VPN settings).

License

MIT. See LICENSE.