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!

Thoughts? Leave a reply

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