Skip to content

Instantly share code, notes, and snippets.

@rhymeswithmogul
Last active July 29, 2021 15:58
Show Gist options
  • Save rhymeswithmogul/2538f5c20d4cb81215e4566a0669231e to your computer and use it in GitHub Desktop.
Save rhymeswithmogul/2538f5c20d4cb81215e4566a0669231e to your computer and use it in GitHub Desktop.
Get a valid certificate for the UniFi Controller
#!/bin/sh
#########################################################################
# renew-unifi-cert.sh (Version 1.1, 2019-11-21)
# Copyright © 2019 Colin Cogle <colin@colincogle.name>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#########################################################################
#
# The latest version of this script can be found at:
# https://gist.github.com/rhymeswithmogul/2538f5c20d4cb81215e4566a0669231e
#
#########################################################################
# Set this to your UniFi Controller installation directory.
# When using the Ubuntu repos, this defaulted to /usr/lib/unifi.
UNIFI_BASE=/usr/lib/unifi
# Create a subdirectory for your certificate files.
CERT_BASE=$UNIFI_BASE/letsencrypt
# Fail immediately if an error is encountered,
# or if I've used an unknown variable.
set -eu
# If we have the old *chain file, see what the date is.
# Let's renew when there are less than 30 days left on the certificate.
if [ -f $CERT_BASE/0001_chain.pem ]
then
NOT_AFTER=$(/usr/bin/openssl x509 -in $CERT_BASE/0001_chain.pem -noout -text | /bin/grep 'Not After:' | /bin/sed -e "s/\s*Not After: //")
CERTIFICATE_DATE=$(/bin/date -d "$NOT_AFTER" +"%Y%m%d")
if [ $CERTIFICATE_DATE -le $(/bin/date -d "-30 days" +"%Y%m%d") ]
then
/bin/echo "The UniFi certificate is less than sixty days old. It will not be renewed at this time."
exit 0
fi
fi
if [ ! -f $CERT_BASE/openssl.cnf ]
then
/bin/echo "The OpenSSL batch file is missing. Creating a new one."
/bin/cat << OPENSSL_CNF > $CERT_BASE/openssl.cnf
[req]
req_extensions = v3_req
default_bits = 2048
default_md = sha256
default_keyfile = private.key
prompt = no
encrypt_key = no
string_mask = nombstr
distinguished_name = req_dn
[v3_req]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @san
[req_dn]
commonName = "unifi.example.com"
[san]
DNS.1 = unifi.example.com
DNS.2 = unifi.example.net
OPENSSL_CNF
/bin/echo "Please edit this file and add your UniFi domain names, then re-run this script."
exit 78 #EX_CONFIG
fi
# If the private key has been deleted, create a new one.
if [ ! -f $CERT_BASE/private.key ]
then
/bin/echo "The private key is missing. Creating a new one."
/usr/bin/openssl ecparam -name secp256r1 -genkey -noout -out $CERT_BASE/private.key
/bin/chown root:unifi $CERT_BASE/private.key
/bin/chmod 660 $CERT_BASE/private.key
/bin/rm -f $CERT_BASE/public.csr
fi
# Make a new CSR if we have generated a new private key, updated OpenSSL.cnf,
# or if the previous CSR is missing for whatever reason.
if [ ! -f $CERT_BASE/public.csr ] || [ "$CERT_BASE/public.csr" -ot "$CERT_BASE/openssl.cnf" ]
then
/bin/echo "The CSR is missing, outdated, or we made a new private key. Generating a new one."
/usr/bin/openssl req -new -key $CERT_BASE/private.key -sha256 -nodes -out $CERT_BASE/public.csr -outform DER -config $CERT_BASE/openssl.cnf
/bin/chown root:unifi $CERT_BASE/public.csr
/bin/chmod 664 $CERT_BASE/public.csr
fi
# Delete the old certificates. Then, start a temporary Web server and get a new certificate.
# TCP port 80 must not be blocked by your firewall. If using IPv4, forward it to your controller, too.
/bin/echo "Deleting old certificates."
/bin/rm -f $CERT_BASE/00??_chain.pem
/bin/rm -f $CERT_BASE/00??_cert.pem
/bin/echo "Requesting a new certificate from Let's Encrypt."
/usr/bin/letsencrypt certonly --csr $CERT_BASE/public.csr --standalone
# Convert it to PKCS #12 format, which UniFi supports.
/bin/echo "Converting to PKCS #12."
/usr/bin/openssl pkcs12 -export -in $CERT_BASE/0001_chain.pem -inkey $CERT_BASE/private.key -caname root -out $CERT_BASE/unifi.p12 -name unifi -passout pass:aircontrolenterprise
# Import into UniFi.
/bin/echo "Importing into UniFi."
/usr/bin/keytool -importkeystore -srcstoretype PKCS12 -srckeystore $CERT_BASE/unifi.p12 -srcstorepass aircontrolenterprise -destkeystore $UNIFI_BASE/data/keystore -destkeypass aircontrolenterprise -deststorepass aircontrolenterprise -alias unifi -noprompt
# Restart the Controller.
/bin/echo "Restarting UniFi."
/bin/systemctl restart unifi
/bin/echo "Done."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment