In this tutorial, we will learn how to replace the self signed SSL certificate provided with the Unifi controller with a free trusted certificate from Let's Encrypt. The immediate advantage of this is that your browser will stop complaining that "Your connection is not secure" when you connect to the controller, and having a CA signed certificate provides additional security against man-in-the-middle attacks by proving the authenticity of the controller. It's also just better practice and looks more professional.

For this to work, you must have a domain name pointing to your controller (you can't get SSL certs for IPs) and your controller server must have port 443 and 80 open and unused (during the renwal)

My controller is hosted on an Ubuntu EC2 instance, so the first thing I needed to was edit its security group to open port 443 and 80. This is Amazon specific, in most other cases, you'll need to add an iptables rule. At this point, I recommend doing a backup/snapshot of your controller instance.

Next we install letsencrypt:

ubuntu@unifi:~$ sudo apt update
ubuntu@unifi:~$ sudo apt install letsencrypt

The rest is pretty easy as a developer named Steve Jenkins has authored a script to automate the whole process.

Generate our certificate with Let's Encrypt

ubuntu@unifi:~$ sudo letsencrypt

Next we download and modify unifi_ssl_import.sh

ubuntu@unifi:~$ sudo wget https://raw.githubusercontent.com/stevejenkins/unifi-linux-utils/master/unifi_ssl_import.sh -O /usr/local/bin/unifi_ssl_import.sh
ubuntu@unifi:~$ sudo chmod +x /usr/local/bin/unifi_ssl_import.sh

First we define our controller's fully qualified domain name

UNIFI_HOSTNAME=unifi.etherarp.net

By default, the script is for Fedora/RedHat and needs to be changed because I'm on Ubuntu

# Uncomment following three lines for Fedora/RedHat/CentOS
#UNIFI_DIR=/opt/UniFi
#JAVA_DIR=${UNIFI_DIR}
#KEYSTORE=${UNIFI_DIR}/data/keystore

# Uncomment following three lines for Debian/Ubuntu
UNIFI_DIR=/var/lib/unifi
JAVA_DIR=/usr/lib/unifi
KEYSTORE=${UNIFI_DIR}/keystore

Now we enable Lets Encrypt mode.

LE_MODE=yes
LE_LIVE_DIR=/etc/letsencrypt/live

Finally we run Steve's script

ubuntu@unifi:~$ sudo /usr/local/bin/unifi_ssl_import.sh

Now if all has went well, try https://unifi.example.com:8443 and your browser should connect without warning and have a green padlock in the address bar.

Automating Renewal

LetsEncrypt certificates are only valid for 90 days. However, we can use a cron job to check and renew the certificate. Edit /etc/crontab and add the following.

0 */12	* * *	root    letsencrypt renew
5 */12	* * *	root    unifi_ssl_import.sh	

This checks/renews the certificate, on the hour, every 12 hours, then 5 minutes later, imports the certificate into the unifi key store.

Redirecting from port 443-to-8443 with NAT

I find it slightly annoying having to add ':8443' onto the URL; I came up with a quite nifty solution, a DNAT rule on my home router.

iptables -t nat -A PREROUTING -d $UNIFI_IP -i eth2 -p tcp -m tcp --dport 443 -j DNAT --to-destination $UNIFI_IP:8443