Running Unifi Network Controller 8.1.113 on Openbsd 7.5

📆
🏷
, ,

So I decided to give the unifi controller a shot on running on OpenBSD and most importantly the plan was to run it alongside all the other daemons on the system, so I don’t need to have a seperate VM / machine running just for the unifi controller. Spoiler: while I was able to get the unifi controller to run on my OpenBSD server I stopped the daemon right away after having all up and running. But why would I go through all the hassles just to not use it, you might ask. Well, if you are not interested about the intricacies of getting the controller up and running, just skip to the conclusion.

All commands are run as root unless otherwise specified.

Acknowledgements

The whole thing was greatly inspired by Renaud Allard’s piece

It is also possible to use the net/unifi port. But as I didn’t want to pull in the whole ports(7) tree just for one port I decided to go down my own route.

Getting all the bits and pieces

Not only do you need to Download the latest release of the UniFi Network Application (formerly known as Controller) but you also need to install MongoDB and you also need a Java Runtime not newer than 17 for the Controller to run. For the controller we create a new user (make sure to use a UID and GID > 1000 to avoid clashes with system and ports users).

At first we create a user for the UniFi Controller to use.

useradd -g =uid -m -d /var/unifi -L daemon -c 'Unifi daemon' -s /sbin/nologin _unifi

Now you need to install and setup all the dependencies for running the Controller. As you want authentication for basically everything in a mixed environment, you are also setting up MongoDB to use authentication. This also means that you need to setup MongoDB users and databases before running the Unifi controller. Java itself doesn’t need any special configuration.

You will start by installing the packages needed:

pkg_add mongodb--%44 jdk-17.0.10.7.1v0 unzip

Before the first start of mongod we must increase some rlimits:

cat <<EOF> /etc/login.conf.d/mongod
mongod:\
	:openfiles=64000:\
	:tc=daemon:
EOF

sysctl kern.maxfiles=64000

cat <<EOF>> /etc/sysctl.conf
kern.maxfiles=64000
EOF

Now we can proceed and start mongod

rcctl enable mongodb
rcctl start mongod
mongo --port 27017

and then continue to create an admin user for MongoDB. Be advised: use a random password without any special characters to avoid problems with the mongo.uri settings for the Controller

db.getSiblingDB("admin").createUser(
  {
    user: "mongod",
    pwd: passwordPrompt(), // or cleartext password
    roles: [ { role: "userAdminAnyDatabase", db: "admin" }, "readWriteAnyDatabase" ]
  }
)
db.adminCommand( { shutdown: 1 } )

Now that you have an admin user you can go on and setup MongoDB for authentication:

cat <<EOF>>/etc/mongodb.conf
security:
    authorization: enabled
EOF
rcctl start mongod

Peachy. Let’s continue and create the neccessary users and databases for the Controller:

mongo --port 27017  --authenticationDatabase "admin" -u "mongod" -p
db.getSiblingDB("admin").createUser(
  {
    user: "ubnt",
    pwd: passwordPrompt(),
    roles: [
      {role: "dbOwner", db: "unifi"},
      {role: "dbOwner", db: "unifi_stat"},
      {role: "clusterMonitor", db: "admin"}
    ]
  }
)
exit

With everything prepared you will now set the stages for the controller itself:

chmod 0700 /var/unifi
su -s /bin/ksh -l _unifi
ftp https://dl.ui.com/unifi/8.1.113/UniFi.unix.zip && unzip UniFi.unix.zip && rm UniFi.unix.zip
rm -f UniFi/bin/mongod && ln -s /usr/local/bin/mongod UniFi/bin/mongod
mkdir UniFi/data
cat <<EOF>>UniFi/data/system.properties
db.mongo.local=false
db.mongo.uri=mongodb://ubnt:##MYSECRETPASSWORD##@127.0.0.1:27017/unifi?authSource=admin
statdb.mongo.uri=mongodb://ubnt:##MYSECRETPASSWORD##@127.0.0.1:27017/unifi_stat?authSource=admin
unifi.db.name=unifi
EOF
exit

The last missing step would be to setup the rc file and starting the Controller

cat <<'EOF'>/etc/rc.d/unifi
#!/bin/ksh
#
# unifi rc file Frank Brodbeck <fab@clacks.xyz>
# heavily inspired by the net/unifi unifi.rc file

JAVA_HOME=/usr/local/jdk-17

daemon="${JAVA_HOME}/bin/java"
daemon_user=_unifi
daemon_execdir="/var/unifi/UniFi"

. /etc/rc.d/rc.subr

rc_reload=NO
rc_bg=YES
pexp="${daemon}${daemon_flags:+ ${daemon_flags}} --add-opens=java.base/java.time=ALL-UNNAMED -cp .* com/ubnt/ace/Launcher start"

rc_start() {
  rc_exec "${daemon} ${daemon_flags} --add-opens=java.base/java.time=ALL-UNNAMED -cp 'lib/*' com/ubnt/ace/Launcher start"
}

rc_cmd $1
EOF
chmod 0555 /etc/rc.de/unifi
rcctl enable unifi
rcctl start unifi

Conclusion

You should now being able to enjoy your UniFi Controller. As mentioned earlier I stopped using the controller on the same system as everything else as the Controller will always bind on all interfaces and there’s currently no plan to change that behaviour. This does not only ends up in plenty of conflicting ports from the software that I already run but this also potentially exposes the Controller’s interface to the internet if I fuckup my firewall rules. A risk I have no interest to sport. But then again, I can now get rid of an Ubuntu machine and just run the Controller on an OpenBSD system.

--EOF