Developing software in the Real World

Run the UniFi Controller headless on Mac

I’m running a UniFi network here with wireless access points, the Security Gateway and a PoE switch. It seems to be a robust system and is almost certainly overkill, but reliability is high on my lists after bad experiences with a NetGear WiFi router.

The UniFi system software is called the Controller and runs on a various operating systems. As I have a Mac mini here, I decided to run it on there. Weirdly, however it runs as a GUI application which means that I have to be logged in. There’s no need for that though as by scouring the Internet I discovered that we can run it headless via launchd.

Firstly we create /Library/LaunchDaemons/com.unifi.controller.service.plist. This file has to be owned by root with group of wheel:

<?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>EnvironmentVariables</key>
    <dict>
        <key>PATH</key>
        <string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/usr/local/sbin</string>
    </dict>
    <key>KeepAlive</key>
    <true/>
    <key>Label</key>
    <string>com.unifi.controller.service.plist</string>
    <key>EnableGlobbing</key>
    <true/>
    <key>ProgramArguments</key>
    <array>
        <string>/bin/bash</string>
        <string>-c</string>
        <string>exec /Applications/UniFi.app/Contents/PlugIns/jre*.jre/Contents/Home/jre/bin/java -Djava.awt.headless=true -Xmx1024M -jar /Applications/UniFi.app/Contents/Resources/lib/ace.jar start</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>WorkingDirectory</key>
    <string>/Applications/UniFi.app/Contents/Resources/</string>
</dict>
</plist>

This is a fairly standard launchd plist file file. However, the controller software is written in Java and Ubiquiti bundle a copy of Java and so we should use that version. The bundled version is stored in a versioned folder within the Plugins folder of the app bundle, so we use bash wildcards to execute:

<key>ProgramArguments</key>
<array>
    <string>/bin/bash</string>
    <string>-c</string>
    <string>exec /Applications/UniFi.app/Contents/PlugIns/jre*.jre/Contents/Home/jre/bin/java -Djava.awt.headless=true -Xmx1024M -jar /Applications/UniFi.app/Contents/Resources/lib/ace.jar start</string>
</array>

This means that when Ubiquiti updates the bundled Java, our service continues to work. We also need to set the working directory to the Resources directory of the app bundle as it doesn’t work otherwise…

Secondly, we install the service:

$ sudo launchctl load -w com.unifi.controller.service.plist

Now, the Controller is always running and we can access it on https://localhost:8443 and manage our UniFi network to our heart’s content!

6 thoughts on “Run the UniFi Controller headless on Mac

  1. Hi Rob….

    What an amazing article….. I have read pages and pages worth of complex solutions and articles on Unifi forum but your methos got me up and running less than 2min.

    Thanks million for this post

  2. Forgive a silly question:
    First install and get the controller working, as gui, no?
    Does it matter the controller version?

    Thank You!

  3. Hello all,
    it indeed worked.
    Just to add, maybe it will help somebody –
    to create plist owned by root and with froup whell you have to manually create plist file with that name (lets say on desktop), copy it to LaunchDaemons and use terminal:
    sudo chown root:wheel /Library/LaunchDaemons/com.unifi.controller.service.plist
    and then start service
    sudo launchctl load -w /Library/LaunchDaemons/com.unifi.controller.service.plist

    Thanks rob for quick help.

  4. Hi all, I have rolled the above including Raul’s comments. Only difference is using folder LaunchAgents.

    Does not load on reboot, but wors when I sign in, I don’t have to launch app.

    I would like it to run on reboot, without logging in. please help

Thoughts? Leave a reply

Your email address will not be published. Required fields are marked *