macOS MDM Deployment (.pkg)

Deploy ctrld to macOS fleets through your MDM using a signed .pkg and a configuration profile.

🚧

Organizations Only

An Organization account is required to use this feature.

Overview

The macOS installer package deploys ctrld to managed fleets through Jamf, Intune, Mosyle, or any MDM that installs signed packages. It is a single generic package per release: provisioning credentials are delivered separately through a configuration profile, never inside the package.

Requirements: macOS 12 (Monterey) or later, Intel or Apple Silicon (the package is universal). The package is signed with a Developer ID Installer certificate, notarized and stapled, so it installs on machines without internet access to Apple.

How it works

  1. Your MDM installs a configuration profile that delivers the provisioning token to the com.controld.ctrld managed preferences domain.
  2. Your MDM installs the package.

Fresh install (no previous install on the device): the script exchanges the token once for a per-device Endpoint, then discards the token. If the profile sets InterceptMode, the script applies it. An invalid value fails the install — a managed deployment must not end up in the wrong mode by accident.

Upgrade (a previous install is already on the device): endpoint identity stays untouched. The script never re-reads ProvisionToken and never exchanges it again — an upgrade never re-provisions. If the profile sets an explicit InterceptMode, the upgrade applies it. An invalid value only logs a warning and keeps the current service mode, so a bad profile edit cannot break a fleet that already works.

The installed service keeps only the endpoint UID from enrollment. The provisioning token stays in the MDM configuration profile — it stays there until an administrator replaces or removes that profile.

Step 1: Create a provisioning code

Follow Mass Provisioning to create a provisioning code with Endpoint Type Mac. The code's Expires After and Limit settings control enrollment, and revoking the code stops new enrollments without affecting enrolled devices.

Step 2: Download the deployment artifacts

Open Provisioning Instructions on the code. Under the MDM section:

  • Download Configuration Profile — a .mobileconfig pre-filled with this code's token.
  • Download .pkg Installer — the current signed universal package.

Jamf Pro admins can alternatively use Computers → Configuration Profiles → Application & Custom Settings → External Applications with preference domain com.controld.ctrld and this schema, entering the provisioning token in the rendered form:

{
    "title": "Control D (ctrld)",
    "description": "Provisioning settings for the ctrld macOS package.",
    "properties": {
        "ProvisionToken": {
            "title": "Provision Token",
            "description": "Token from the Control D mass-provisioning code. Required: fresh installs read it at package install time to enroll the device.",
            "type": "string"
        },
        "CustomHostname": {
            "title": "Custom Hostname",
            "description": "Optional hostname reported to the Control D API instead of the device hostname. Allowed characters: letters, digits, hyphens, and dots — ctrld rejects anything else before install. The server folds other separators (for example spaces) when it derives the Endpoint name.",
            "type": "string"
        }
    }
}

Step 3: Deploy

  1. Upload the configuration profile to your MDM as a device (System) profile and scope it to the fleet.
  2. Upload the package and scope it to the same fleet.

Scope the profile before the package. The install script waits up to 2 minutes for the profile; if it never arrives, the install is reported as failed in the MDM and the service does not start (see Troubleshooting).

Installation is unattended: no user interaction, no reboot. On install each device enrolls and appears as an Endpoint in the Control D dashboard. To verify on a device:

sudo ctrld diag
pkgutil --pkg-info com.controld.ctrld

ctrld diag reports service state, managed-preference presence, and API reachability in one command. pkgutil confirms the installed package version.

Upgrades

Push a newer package version through the MDM. The installer stops the service, replaces the binary, and restarts the service. The Endpoint, its configuration, and the dashboard entry are preserved. No provisioning token is needed for upgrades.

Note: ctrld upgrade (the built-in self-updater) also works on package-based installs. MDM-managed fleets should standardize on package pushes so the package receipt version reflects reality; avoid scheduling ctrld upgrade on managed devices.

Rotating or invalidating a code

If you edit or replace a provisioning code, re-download its configuration profile from the code's Provisioning Instructions. Re-push it through your MDM. You do not need to re-push the package — it never carries the token. An edit to a code does not change a profile already on a device.

When you invalidate or delete a code, it does not remove profiles already pushed. Enrolled devices continue to work. A fresh install that still reads the old profile's token fails, with TOKEN_DISABLED or API_REJECTED.

Offboarding

Run the bundled uninstall helper from an MDM script or policy, as root:

/usr/local/controld/uninstall.sh [deactivation-pin]

If the provisioning code was created with a Prevent Deactivation PIN, pass it as the first argument — store it as a server-side script parameter in the MDM (for example a Jamf script parameter), never in a script visible to users. The helper stops the service, restores DNS to OS defaults, and removes the configuration, binary, and package receipt.

You can then remove the corresponding Endpoint in the Control D dashboard. Endpoints (and their analytics) remain in the dashboard until you remove them. An uninstalled device no longer reports. You can also remove the Endpoint first, but this works only partially. On its next service start, ctrld detects the missing Endpoint. It stops itself, restores the device's normal DNS, and removes the launchd service registration. The binary and package receipt stay on disk. Run the uninstall helper (or push an MDM removal) to fully remove ctrld.

Troubleshooting

Install script output lands in /var/log/install.log on the device, prefixed ctrld postinstall: / ctrld preinstall:. The provisioning token is never written to the log.

A failed install in the MDM means the device did not end up with a running provisioned service. The files stay on disk (macOS Installer does not roll back), so remediation is always: fix the cause, then re-push the package.

Every postinstall failure logs one fixed-format line:

provisioning failed: stage=<stage> code=<CODE> (exit <n>)

Find it on the device with:

grep "ctrld postinstall:" /var/log/install.log

On failure, the log also has a ctrld postinstall: diag: block: the output of ctrld diag. An MDM console that already collects install logs gets the full diagnostic picture with no extra step.

To inspect a device by hand, run:

sudo ctrld diag

It reports whether the managed-preference profile and its ProvisionToken are present (never the token value), the last provisioning result, service state, and API reachability. Add --json for machine-readable output. Safe to paste into a support ticket.

For what each code means and how to fix it, see Provisioning Troubleshooting.

One code needs an MDM-specific fix: SERVICE_RELOAD_FAILED means an upgrade replaced the binary but the service failed to reload. Re-push or reinstall the package to recover.


Did this page help you?