I’ve been experimenting with unifi controller, both on NS 6 and NS 7, here’s an HowTo that will:
- Install UniFi controller
- Use Let’s Encrypt cert to have a secure https connection to UniFi Controller
- Configure the Controller and the Access Points to function in a cloud based solution, with remote AP Provisioning
Install EPEL
NS 6.8
cd /tmp
yum -y install http://ftp.heanet.ie/pub/fedora/epel/6/i386/epel-release-6-8.noarch.rpm
yum update
NS 7 should already come with epel installed, or:
yum install epel-release
Install MongoDB
##NS 6
yum -y --enablerepo=epel install mongodb mongodb-server
chkconfig mongod on
service mongod start
On NS 7
yum -y --enablerepo=epel install mongodb mongodb-server
systemctl enable mongod.service
systemctl start mongod.service
Install other needed packages
yum -y install unzip java
Install UniFi controller, as of today, latest version is 5.0.6
wget https://www.ubnt.com/downloads/unifi/5.0.6/UniFi.unix.zip
unzip UniFi.unix.zip
mv ./UniFi /opt
chkconfig unifi on
On NS 6.8
service unifi start
On NS 7, create a startup script:
Create a new file
vi /etc/systemd/system/unifi.service
And paste the following in it:
# Systemd unit file for UniFi Controller
[Unit]
Description=UniFi AP Web Controller
After=syslog.target network.target
[Service]
Type=simple
User=root
WorkingDirectory=/opt/UniFi
ExecStart=/usr/bin/java -Xmx1024M -jar /opt/UniFi/lib/ace.jar start
ExecStop=/usr/bin/java -jar /opt/UniFi/lib/ace.jar stop
SuccessExitStatus=143
[Install]
WantedBy=multi-user.target
then run
systemctl enable unifi.service
systemctl start unifi.service
Networking
At this point, the server has to be accessible from the networks you want to manage it from, aswell as the networks your Access Points are going to be installed in (their public IP).
For testing purposes, you can open all internet too, i don’t reccomend it as it is not necessary to function, if you wan to manage it from your smartphone wherever you are, get a vpn
Ports are:
TCP 8080,8443,8880,8843
UDP 3478,10001
Configure them in https://FQDN:980 Firewall Objects
And add rules to use the service
(Any means all internet)
Use Let’s Encrypt certificates for UniFi
I have installed Let’s Encrypt following Giacomo here NethServer 6.7 02/16 updates & Let's Encrypt
If you are using NS 7, just use the built in module
To sync UniFi cert with Let’sEncr ones i have used a script found here http://www.stevejenkins.com/blog/2016/06/use-existing-ssl-certificate-linux-unifi-controller/ changing the first configuration lines, the script handles
- Creating a backup of the UniFi keystore file, which is the one being modified by the script
- Checking wether the .pem files exist, if they are newer than the ones already imported, import them
- Restart the UniFi service
If you don’t like running scripts taken from the internet, reading through it takes very little time and you can write your own script
Whatever script you use, it has to be run couple of minutes after the let’s encrypt daily script runs in cron, so that if let’s encrypt changes its certificates, so does UniFi.
Here’s a script that should do the job for most systems running NS 6.8, using let’s encrypt already (Need to modify line 23, UNIFI_HOSTNAME=FQDN, with your server FQDN)
Use this other script for NS 6
#!/usr/bin/env bash
# unifi_ssl_import.sh
# UniFi Controller SSL Certificate Import Script for Unix/Linux Systems
# by Steve Jenkins <http://www.stevejenkins.com/>
# Incorporates ideas from https://source.sosdg.org/brielle/lets-encrypt-scripts
# Version 2.2
# Last Updated June 26, 2016
# REQUIREMENTS
# 1) Assumes you have a UniFi Controller installed and running on your system.
# 2) Assumes you have a valid private key, signed certificate, and certificate
# authority chain file. See http://wp.me/p1iGgP-2wU for detailed instructions
# on how to generate these files and use them with this script.
# KEYSTORE BACKUP
# Even though this script attempts to be clever and careful in how it backs up your existing keystore,
# it's never a bad idea to manually back up your keystore (located at $UNIFI_DIR/data/keystore)
# to a separate directory before running this script. If anything goes wrong, you can restore from your
# backup, restart the UniFi Controller service, and be back online immediately.
# CONFIGURATION OPTIONS
UNIFI_HOSTNAME=FQDN
UNIFI_DIR=/opt/UniFi
#UNIFI_DIR=/usr/lib/unifi
UNIFI_SERVICE_NAME=unifi
# FOR LET'S ENCRYPT SSL CERTIFICATES ONLY
LE_MODE=yes
LE_LIVE_DIR=/etc/letsencrypt.sh/certs
# THE FOLLOWING OPTIONS NOT REQUIRED IF LE_MODE IS ENABLED
PRIV_KEY=/etc/ssl/private/hostname.example.com.key
SIGNED_CRT=/etc/ssl/certs/hostname.example.com.crt
CHAIN_FILE=/etc/ssl/certs/startssl-chain.crt
# CONFIGURATION OPTIONS YOU PROBABLY SHOULDN'T CHANGE
KEYSTORE=${UNIFI_DIR}/data/keystore
ALIAS=unifi
PASSWORD=aircontrolenterprise
#### SHOULDN'T HAVE TO TOUCH ANYTHING PAST THIS POINT ####
printf "\nStarting UniFi Controller SSL Import...\n"
# Check to see whether Let's Encrypt Mode (LE_MODE) is enabled
if [[ ${LE_MODE} == "YES" || ${LE_MODE} == "yes" || ${LE_MODE} == "Y" || ${LE_MODE} == "y" || ${LE_MODE} == "TRUE" || ${LE_MODE} == "true" || ${LE_MODE} == "ENABLED" || ${LE_MODE} == "enabled" || ${LE_MODE} == 1 ]] ; then
LE_MODE=true
printf "\nRunning in Let's Encrypt Mode...\n"
PRIV_KEY=${LE_LIVE_DIR}/${UNIFI_HOSTNAME}/privkey.pem
SIGNED_CRT=${LE_LIVE_DIR}/${UNIFI_HOSTNAME}/cert.pem
CHAIN_FILE=${LE_LIVE_DIR}/${UNIFI_HOSTNAME}/chain.pem
else
LE_MODE=false
printf "\nRunning in Standard Mode...\n"
fi
if [ ${LE_MODE} == "true" ]; then
# Check to see whether LE certificate has changed
printf "\nInspecting current SSL certificate...\n"
if md5sum -c ${LE_LIVE_DIR}/${UNIFI_HOSTNAME}/cert.pem.md5 &>/dev/null; then
# MD5 remains unchanged, exit the script
printf "\nCertificate is unchanged, no update is necessary.\n"
exit 0
else
# MD5 is different, so it's time to get busy!
printf "\nUpdated SSL certificate available. Proceeding with import...\n"
fi
fi
# Verify required files exist
if [ ! -f ${PRIV_KEY} ] || [ ! -f ${SIGNED_CRT} ] || [ ! -f ${CHAIN_FILE} ]; then
printf "\nMissing one or more required files. Check your settings.\n"
exit 1
else
# Everything looks OK to proceed
printf "\nImporting the following files:\n"
printf "Private Key: %s\n" "$PRIV_KEY"
printf "Signed Certificate: %s\n" "$SIGNED_CRT"
printf "CA File: %s\n" "$CHAIN_FILE"
fi
# Create temp files
P12_TEMP=$(mktemp)
CA_TEMP=$(mktemp)
# Stop the UniFi Controller
printf "\nStopping UniFi Controller...\n"
service ${UNIFI_SERVICE_NAME} stop
if [ ${LE_MODE} == "true" ]; then
# Write a new MD5 checksum based on the updated certificate
printf "\nUpdating certificate MD5 checksum...\n"
md5sum ${LE_LIVE_DIR}/${UNIFI_HOSTNAME}/cert.pem > ${LE_LIVE_DIR}/${UNIFI_HOSTNAME}/cert.pem.md5
# Create local copy of cross-signed CA File (required for keystore import)
# Verify original @ https://www.identrust.com/certificates/trustid/root-download-x3.html
cat > "${CA_TEMP}" <<'_EOF'
-----BEGIN CERTIFICATE-----
MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow
PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD
Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O
rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq
OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b
xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw
7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD
aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG
SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69
ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr
AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz
R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5
JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo
Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
-----END CERTIFICATE-----
_EOF
fi
# Create double-safe keystore backup
if [ -s "${KEYSTORE}.orig" ]; then
printf "\nBackup of original keystore exists!\n"
printf "\nCreating non-destructive backup as keystore.bak...\n"
cp ${KEYSTORE} ${KEYSTORE}.bak
else
cp ${KEYSTORE} ${KEYSTORE}.orig
printf "\nNo original keystore backup found.\n"
printf "\nCreating backup as keystore.orig...\n"
fi
# Export your existing SSL key, cert, and CA data to a PKCS12 file
printf "\nExporting SSL certificate and key data into temporary PKCS12 file...\n"
openssl pkcs12 -export \
-in ${SIGNED_CRT} \
-inkey ${PRIV_KEY} \
-CAfile ${CHAIN_FILE} \
-out ${P12_TEMP} -passout pass:${PASSWORD} \
-caname root -name ${ALIAS}
# Delete the previous certificate data from keystore to avoid "already exists" message
printf "\nRemoving previous certificate data from UniFi keystore...\n"
keytool -delete -alias ${ALIAS} -keystore ${KEYSTORE} -deststorepass ${PASSWORD}
# Import the temp PKCS12 file into the UniFi keystore
printf "\nImporting SSL certificate into UniFi keystore...\n"
keytool -importkeystore \
-srckeystore ${P12_TEMP} -srcstoretype PKCS12 \
-srcstorepass ${PASSWORD} \
-destkeystore ${KEYSTORE} \
-deststorepass ${PASSWORD} \
-destkeypass ${PASSWORD} \
-alias ${ALIAS} -trustcacerts
# Import the certificate authority data into the UniFi keystore
printf "\nImporting certificate authority into UniFi keystore...\n\n"
if [ ${LE_MODE} == "true" ]; then
# Import with additional cross-signed CA file
java -jar ${UNIFI_DIR}/lib/ace.jar import_cert \
${SIGNED_CRT} \
${CHAIN_FILE} \
${CA_TEMP}
else
# Import in standard mode
java -jar ${UNIFI_DIR}/lib/ace.jar import_cert \
${SIGNED_CRT} \
${CHAIN_FILE}
fi
# Clean up temp files
printf "\nRemoving temporary files...\n"
rm -f ${P12_TEMP}
rm -f ${CA_TEMP}
# Restart the UniFi Controller to pick up the updated keystore
printf "\nRestarting UniFi Controller to apply new Let's Encrypt SSL certificate...\n"
service ${UNIFI_SERVICE_NAME} start
# That's all, folks!
printf "\nDone!\n"
exit 0
Use this other script for NS 7
Remember to change line 23, UNIFI_HOSTNAME=FQDN
#!/usr/bin/env bash
# unifi_ssl_import.sh
# UniFi Controller SSL Certificate Import Script for Unix/Linux Systems
# by Steve Jenkins <http://www.stevejenkins.com/>
# Incorporates ideas from https://source.sosdg.org/brielle/lets-encrypt-scripts
# Version 2.2
# Last Updated June 26, 2016
# REQUIREMENTS
# 1) Assumes you have a UniFi Controller installed and running on your system.
# 2) Assumes you have a valid private key, signed certificate, and certificate
# authority chain file. See http://wp.me/p1iGgP-2wU for detailed instructions
# on how to generate these files and use them with this script.
# KEYSTORE BACKUP
# Even though this script attempts to be clever and careful in how it backs up your existing keystore,
# it's never a bad idea to manually back up your keystore (located at $UNIFI_DIR/data/keystore)
# to a separate directory before running this script. If anything goes wrong, you can restore from your
# backup, restart the UniFi Controller service, and be back online immediately.
# CONFIGURATION OPTIONS
UNIFI_HOSTNAME=FQDN
UNIFI_DIR=/opt/UniFi
#UNIFI_DIR=/usr/lib/unifi
UNIFI_SERVICE_NAME=unifi
# FOR LET'S ENCRYPT SSL CERTIFICATES ONLY
LE_MODE=yes
LE_LIVE_DIR=/etc/letsencrypt/live
# THE FOLLOWING OPTIONS NOT REQUIRED IF LE_MODE IS ENABLED
PRIV_KEY=/etc/ssl/private/hostname.example.com.key
SIGNED_CRT=/etc/ssl/certs/hostname.example.com.crt
CHAIN_FILE=/etc/ssl/certs/startssl-chain.crt
# CONFIGURATION OPTIONS YOU PROBABLY SHOULDN'T CHANGE
KEYSTORE=${UNIFI_DIR}/data/keystore
ALIAS=unifi
PASSWORD=aircontrolenterprise
#### SHOULDN'T HAVE TO TOUCH ANYTHING PAST THIS POINT ####
printf "\nStarting UniFi Controller SSL Import...\n"
# Check to see whether Let's Encrypt Mode (LE_MODE) is enabled
if [[ ${LE_MODE} == "YES" || ${LE_MODE} == "yes" || ${LE_MODE} == "Y" || ${LE_MODE} == "y" || ${LE_MODE} == "TRUE" || ${LE_MODE} == "true" || ${LE_MODE} == "ENABLED" || ${LE_MODE} == "enabled" || ${LE_MODE} == 1 ]] ; then
LE_MODE=true
printf "\nRunning in Let's Encrypt Mode...\n"
PRIV_KEY=${LE_LIVE_DIR}/${UNIFI_HOSTNAME}/privkey.pem
SIGNED_CRT=${LE_LIVE_DIR}/${UNIFI_HOSTNAME}/cert.pem
CHAIN_FILE=${LE_LIVE_DIR}/${UNIFI_HOSTNAME}/chain.pem
else
LE_MODE=false
printf "\nRunning in Standard Mode...\n"
fi
if [ ${LE_MODE} == "true" ]; then
# Check to see whether LE certificate has changed
printf "\nInspecting current SSL certificate...\n"
if md5sum -c ${LE_LIVE_DIR}/${UNIFI_HOSTNAME}/cert.pem.md5 &>/dev/null; then
# MD5 remains unchanged, exit the script
printf "\nCertificate is unchanged, no update is necessary.\n"
exit 0
else
# MD5 is different, so it's time to get busy!
printf "\nUpdated SSL certificate available. Proceeding with import...\n"
fi
fi
# Verify required files exist
if [ ! -f ${PRIV_KEY} ] || [ ! -f ${SIGNED_CRT} ] || [ ! -f ${CHAIN_FILE} ]; then
printf "\nMissing one or more required files. Check your settings.\n"
exit 1
else
# Everything looks OK to proceed
printf "\nImporting the following files:\n"
printf "Private Key: %s\n" "$PRIV_KEY"
printf "Signed Certificate: %s\n" "$SIGNED_CRT"
printf "CA File: %s\n" "$CHAIN_FILE"
fi
# Create temp files
P12_TEMP=$(mktemp)
CA_TEMP=$(mktemp)
# Stop the UniFi Controller
printf "\nStopping UniFi Controller...\n"
systemctl stop ${UNIFI_SERVICE_NAME}.service
if [ ${LE_MODE} == "true" ]; then
# Write a new MD5 checksum based on the updated certificate
printf "\nUpdating certificate MD5 checksum...\n"
md5sum ${LE_LIVE_DIR}/${UNIFI_HOSTNAME}/cert.pem > ${LE_LIVE_DIR}/${UNIFI_HOSTNAME}/cert.pem.md5
# Create local copy of cross-signed CA File (required for keystore import)
# Verify original @ https://www.identrust.com/certificates/trustid/root-download-x3.html
cat > "${CA_TEMP}" <<'_EOF'
-----BEGIN CERTIFICATE-----
MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow
PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD
Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O
rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq
OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b
xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw
7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD
aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG
SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69
ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr
AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz
R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5
JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo
Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
-----END CERTIFICATE-----
_EOF
fi
# Create double-safe keystore backup
if [ -s "${KEYSTORE}.orig" ]; then
printf "\nBackup of original keystore exists!\n"
printf "\nCreating non-destructive backup as keystore.bak...\n"
cp ${KEYSTORE} ${KEYSTORE}.bak
else
cp ${KEYSTORE} ${KEYSTORE}.orig
printf "\nNo original keystore backup found.\n"
printf "\nCreating backup as keystore.orig...\n"
fi
# Export your existing SSL key, cert, and CA data to a PKCS12 file
printf "\nExporting SSL certificate and key data into temporary PKCS12 file...\n"
openssl pkcs12 -export \
-in ${SIGNED_CRT} \
-inkey ${PRIV_KEY} \
-CAfile ${CHAIN_FILE} \
-out ${P12_TEMP} -passout pass:${PASSWORD} \
-caname root -name ${ALIAS}
# Delete the previous certificate data from keystore to avoid "already exists" message
printf "\nRemoving previous certificate data from UniFi keystore...\n"
keytool -delete -alias ${ALIAS} -keystore ${KEYSTORE} -deststorepass ${PASSWORD}
# Import the temp PKCS12 file into the UniFi keystore
printf "\nImporting SSL certificate into UniFi keystore...\n"
keytool -importkeystore \
-srckeystore ${P12_TEMP} -srcstoretype PKCS12 \
-srcstorepass ${PASSWORD} \
-destkeystore ${KEYSTORE} \
-deststorepass ${PASSWORD} \
-destkeypass ${PASSWORD} \
-alias ${ALIAS} -trustcacerts
# Import the certificate authority data into the UniFi keystore
printf "\nImporting certificate authority into UniFi keystore...\n\n"
if [ ${LE_MODE} == "true" ]; then
# Import with additional cross-signed CA file
java -jar ${UNIFI_DIR}/lib/ace.jar import_cert \
${SIGNED_CRT} \
${CHAIN_FILE} \
${CA_TEMP}
else
# Import in standard mode
java -jar ${UNIFI_DIR}/lib/ace.jar import_cert \
${SIGNED_CRT} \
${CHAIN_FILE}
fi
# Clean up temp files
printf "\nRemoving temporary files...\n"
rm -f ${P12_TEMP}
rm -f ${CA_TEMP}
# Restart the UniFi Controller to pick up the updated keystore
printf "\nRestarting UniFi Controller to apply new Let's Encrypt SSL certificate...\n"
systemctl start ${UNIFI_SERVICE_NAME}.service
# That's all, folks!
printf "\nDone!\n"
exit 0
Access Points
UniFi AP has a default inform URL http://unifi:8080/inform
That means we can change what “unifi” resolves to and have the AP connect to our http://FQDN:8080/inform, getting provisioned by the controller
Just need to be sure that the DNS for the Access Points can resolve our FQDN, and the DHCP provides them with option 43 as described below
Methods to do so with httpd, Cisco and Mikrotik on https://help.ubnt.com/hc/en-us/articles/204909754-UniFi-Layer-3-methods-for-UAP-adoption-and-management
A nice utility to have is the chrome extension Discovery Tool
Ready
If everything went smooth, you can access the controller on https://FQDN:8443 and start configuring it with the wizard.
Access Points, if correctly configured, should appear inside the web interface ready to be upgraded and provisioned by the controller
Notes
- Haven’t tried with a Nethserver being the Access Points DNS/DHCP, if someone could fill in on this
- ToDo - Test customization portal
- ToDo - Test paypal pro and other payment options, maybe someone from other countries could try these?