Deploy Tailscale on macOS using MDM

This page contains technical information which you might find useful if you are a system administrator deploying Tailscale for macOS in a corporate environment using MDM.

We are actively working on providing more options for system administrators to programmatically manage their Tailscale deployments. If you are deploying Tailscale and feel the need for a specific configuration option that is currently missing on this page, open a GitHub issue.

User Defaults

User Defaults enforced via MDM can allow you to configure specific Tailscale settings on behalf of the user, providing an easier setup process.

The commands listed on this page use the bundle identifier for the Mac App Store variant of Tailscale, io.tailscale.ipn.macos. If you are configuring the Standalone variant of the app, replace it with the io.tailscale.ipn.macsys bundle identifier.

Automatically start Tailscale when the user logs in

The first time the application is opened on your Mac, Tailscale installs a macOS login helper. This allows Tailscale to start automatically when the user logs into their account. To enable this feature, set the following user default:

defaults write io.tailscale.ipn.macos TailscaleStartOnLogin 1

Skip the onboarding flow upon first launch

When you start Tailscale on your Mac for the first time, an onboarding flow is presented. It explains the Tailscale privacy policy, and guides the user in setting up the VPN configuration on their Mac. You might want to disable this onboarding flow if you are going to automatically set up the VPN configuration on the system by using a configuration profile. To do so, change this user default:

defaults write io.tailscale.ipn.macos TailscaleOnboardingSeen 1

Suppress copied IP address notifications

When you use the Tailscale menu bar item to copy the IP address of a device, a notification displaying the IP address is presented. You can suppress the notification with this user default:

defaults write io.tailscale.ipn.macos IPAddressCopiedAlertSuppressed 1

Set a custom coordination server URL

Use this user default to programmatically configure Tailscale to use a custom coordination server, such as a Headscale server.

defaults write io.tailscale.ipn.macos ControlURL 'url-goes-here'

Disable update checks

This section exclusively applies to the Standalone variant of Tailscale for macOS. When you download Tailscale from the Mac App Store, the system automatically updates it for you, provided that automatic app updates are enabled.

If you are using the Standalone version of Tailscale for macOS, the client will periodically check for updates automatically and notify the user that a new version is available, using the Sparkle framework. We recommend that you leave this feature on, in order to ensure your users receive any security updates in a timely manner. However, you might prefer to manually deploy updates and disable notifications of new available versions. To do so, use the following user default:

defaults write io.tailscale.ipn.macsys SUEnableAutomaticChecks 0

Configuration profiles

If you are deploying Tailscale for macOS using MDM, you can use configuration profiles to automate parts of the setup process, reducing prompt fatigue for the user.

Allow push notifications automatically

Tailscale for macOS may sometimes use system notifications to inform the user. For instance, you will receive a notification when:

  • the device key is about to expire
  • a file was received using Taildrop
  • an IP address was copied to the clipboard

This is an example of a configuration profile to automatically allow notifications for Tailscale.

Make sure you replace the bundle identifier io.tailscale.ipn.macos with io.tailscale.ipn.macsys if you are creating a configuration profile for the Standalone variant of Tailscale for macOS.
<dict>
  <key>NotificationSettings</key>
  <array>
    <dict>
      <key>AlertType</key>
      <integer>1</integer>
      <key>BadgesEnabled</key>
      <true/>
      <key>BundleIdentifier</key>
      <string>io.tailscale.ipn.macos</string>
      <key>CriticalAlertEnabled</key>
      <true/>
      <key>NotificationsEnabled</key>
      <true/>
      <key>ShowInNotificationCenter</key>
      <true/>
    </dict>
  </array>
  <key>PayloadDisplayName</key>
  <string>Allow Tailscale Notifications</string>
  <key>PayloadIdentifier</key>
  <string>b3dc3535-1b06-4f2d-a684-4518a6589dff</string>
  <key>PayloadOrganization</key>
  <string>Tailscale Inc.</string>
  <key>PayloadType</key>
  <string>com.apple.notificationsettings</string>
  <key>PayloadUUID</key>
  <string>056ec734-91b7-45a3-8787-98ebf2e84024</string>
  <key>PayloadVersion</key>
  <integer>1</integer>
</dict>

Install the Tailscale VPN configuration

On the first time it launches on a Mac, the Tailscale app will install a NetworkExtension VPN configuration. You can choose to skip this step by providing a configuration profile which will configure the VPN configuration before the app launches. During the first launch, the Tailscale app will detect the pre-existing configuration and skip the installation step.

The following is a valid .mobileconfig plist file to set up such a VPN configuration.

Make sure you replace io.tailscale.ipn.macos with io.tailscale.ipn.macsys, and io.tailscale.ipn.macos.network-extension with io.tailscale.ipn.macsys.network-extension if you are creating a configuration profile for the Standalone variant of Tailscale for macOS.
<?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>PayloadDisplayName</key>
  <string>Tailscale VPN Configuration Profile</string>
  <key>PayloadType</key>
  <string>Configuration</string>
  <key>PayloadVersion</key>
  <integer>1</integer>
  <key>PayloadIdentifier</key>
  <string>com.your-company-name.tailscale.797d4461-837c-4f5a-b18e-7e300a057018</string>
  <key>PayloadUUID</key>
  <string>0f451881-7ac4-4171-80fd-b55251053231</string>
  <key>PayloadContent</key>
  <array>
        <dict>
        <key>PayloadDisplayName</key>
        <string>Tailscale VPN Configuration</string>
        <key>PayloadType</key>
        <string>com.apple.vpn.managed</string>
        <key>PayloadVersion</key>
        <integer>1</integer>
        <key>PayloadIdentifier</key>
        <string>com.your-company-name.tailscale-tunnel</string>
        <key>PayloadUUID</key>
        <string>7ec957e2-b165-4d1f-9946-3a7a16ae0f9b</string>
        <key>UserDefinedName</key>
        <string>Tailscale MobileConfig</string>
        <key>VPNType</key>
        <string>VPN</string>
        <key>VPNSubType</key>
        <string>io.tailscale.ipn.macos</string>
        <key>VPN</key>
         <dict>
            <key>RemoteAddress</key>
            <string>Tailscale Mesh</string>
            <key>AuthenticationMethod</key>
            <string>Password</string>
            <key>ProviderBundleIdentifier</key>
            <string>io.tailscale.ipn.macos.network-extension</string>
        </dict>
    </dict>
  </array>
</dict>
</plist>

Approve the Tailscale system extension automatically

This section exclusively applies to the Standalone variant of Tailscale for macOS. The variant of Tailscale distributed in the Mac App Store does not use a system extension, and only requires installing a VPN configuration.

The section above explained how you can create a configuration profile to pre-install the Tailscale VPN configuration. However, when starting the Standalone variant of Tailscale for the first time, the app will also attempt to install a system extension. By default, macOS blocks this, and requires the user to manually approve Tailscale in the System Settings app:

A screenshot of the macOS system extension warning

You can allow the system extension by default by adding a system extension policy to the configuration profile. The first thing to do is to set the scope of your configuration profile payload to System, as system extensions affect all users on a Mac. Add the following at the top level of your configuration file:

<key>PayloadScope</key>
<string>System</string>

Then, add the system extension policy inside the PayloadContent array of the configuration file:

<dict>
  <key>PayloadUUID</key>
  <string>1d08bf7d-7898-43b3-88e3-76cfb74a7c33</string>
  <key>PayloadType</key>
  <string>com.apple.system-extension-policy</string>
  <key>PayloadOrganization</key>
  <string>Tailscale</string>
  <key>PayloadIdentifier</key>
  <string>8a790b57-16da-4371-8baf-d6f65e7b50ee</string>
  <key>PayloadDisplayName</key>
  <string>Allows system extensions signed by Tailscale to run without user approval.</string>
  <key>PayloadDescription</key>
  <string/>
  <key>PayloadVersion</key>
  <integer>1</integer>
  <key>PayloadEnabled</key>
  <true/>
  <key>AllowedTeamIdentifiers</key>
  <array>
    <string>W5364U7YZB</string>
  </array>
</dict>

Note that macOS enforces that a payload with system scope can only by deployed by a MDM server. This means that users won’t be able to install the configuration profile you just created by themselves: your organization will need to push it using the MDM server.

Last updated