Ubiquiti UniFi with LetsEncrypt

I’ve been running a Community UniFi Controller for Geekzone forum members free of charge for their UniFI gear a few months now and a few people wanted to know how I am securing it with LetsEncrypt so here is a quick guide for Ubuntu 16.04 for a rather secure UniFi cloud server.

I’ve adapted the installation script from Here to include the official Letsencrypt package + the websocket rules for nginx as well as fixed it for Ubuntu 16.04 so thanks to the OP who automated this! I personally did it the manual way but this way will be easier for people not too familiar with Linux to create a secure instance.

You’ll need the following ports open and forwarded to your instance:

80/tcp
443/tcp
8080/tcp (Inform)
8443/tcp (UniFi Software – SSL)
8880/tcp
8843/tcp
6787/tcp
More here.

Make a new file called /opt/le.sh with the following contents:

#!/bin/sh
# Script source used from https://community.ubnt.com/t5/UniFi-Wireless/UniFi-Ubuntu-16-04-fully-automatic-Installation-NGINX-Proxy-amp/td-p/1596848

# Edit these following 2 lines:
NAME="my.fqdn.com"
EMAIL="[email protected]"

# Comment out the following 4 lines if you already have the UniFi software installed.
# Note - the UniFi software requires at-least 20GiB disk space.
echo "deb http://www.ubnt.com/downloads/unifi/debian unifi5 ubiquiti" > /etc/apt/sources.list.d/unifi.list
echo y | apt-key adv --keyserver keyserver.ubuntu.com --recv C0A52C50
apt update
echo y | apt install unifi

# Script Start...
apt update
echo y | apt upgrade
apt -f install
echo y | apt install nginx letsencrypt

service nginx stop
echo y | letsencrypt certonly -d $NAME --standalone --standalone-supported-challenges http-01 --email $EMAIL
service nginx start

service unifi stop
echo aircontrolenterprise | openssl pkcs12 -export -inkey /etc/letsencrypt/live/$NAME/privkey.pem -in /etc/letsencrypt/live/$NAME/cert.pem -name unifi -out /etc/letsencrypt/live/$NAME/keys.p12 -password stdin
echo y | keytool -importkeystore -srckeystore /etc/letsencrypt/live/$NAME/keys.p12 -srcstoretype pkcs12 -destkeystore /usr/lib/unifi/data/keystore -storepass aircontrolenterprise -srcstorepass aircontrolenterprise
service unifi start
openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096

#NGINX PROXY
service nginx stop
printf "server_tokens off;\n\
add_header X-Frame-Options SAMEORIGIN;\n\
add_header X-XSS-Protection \"1; mode=block\";\n\
server {\n\
 listen 80;\n\
 server_name $NAME;\n\
 return 301 https://$NAME\$request_uri;\n\
}\n\
server {\n\
 listen 443 ssl default_server http2;\n\
 server_name $NAME;\n\
 ssl_dhparam /etc/ssl/certs/dhparam.pem;\n\
 ssl_certificate /etc/letsencrypt/live/$NAME/fullchain.pem;\n\
 ssl_certificate_key /etc/letsencrypt/live/$NAME/privkey.pem;\n\
 ssl_session_cache shared:SSL:10m;\n\
 ssl_session_timeout 10m;\n\
 keepalive_timeout 300;\n\
 ssl_protocols TLSv1 TLSv1.1 TLSv1.2;\n\
 ssl_prefer_server_ciphers on;\n\
 ssl_stapling on;\n\
 ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:DHE-RSA-AES256-SHA;
 add_header Strict-Transport-Security max-age=31536000;\n\
 add_header X-Frame-Options DENY;\n\
 error_log /var/log/unifi/nginx.log;\n\
 proxy_cache off;\n\
 proxy_store off;\n\
 location / {\n\
 proxy_set_header Referer \"\";\n\
 proxy_pass https://localhost:8443;\n\
 proxy_set_header Host \$host;\n\
 proxy_set_header X-Real-IP \$remote_addr;\n\
 proxy_set_header X-Forward-For \$proxy_add_x_forwarded_for;\n\
 proxy_http_version 1.1;\n\
 proxy_set_header Upgrade \$http_upgrade;\n\
 proxy_set_header Connection \"upgrade\";\n\
 }\n\
}\n\
 " > /etc/nginx/sites-enabled/default
service nginx start

Make it executable with “chmod +x /opt/le.sh” then run it with “bash /opt/le.sh” under root (this will take quite a while to install and set up everything – mainly the SSL side of things). Once it is run it should set you up with a secure UniFi controller with a full reverse proxy:

But we’re not done yet! No way… Letsencrypt certificates expire after 3 months so lets automate the renewal. Save the below under /opt/le-renew.sh and chmod it to make it executable with “chmod +x /opt/le-renew.sh”:

#!/bin/sh
NAME="my.fqdn.com"

service nginx stop
echo y | letsencrypt renew --standalone --standalone-supported-challenges http-01
service nginx start

service unifi stop
echo aircontrolenterprise | openssl pkcs12 -export -inkey /etc/letsencrypt/live/$NAME/privkey.pem -in /etc/letsencrypt/live/$NAME/cert.pem -name unifi -out /etc/letsencrypt/live/$NAME/keys.p12 -password stdin
echo y | keytool -importkeystore -srckeystore /etc/letsencrypt/live/$NAME/keys.p12 -srcstoretype pkcs12 -destkeystore /usr/lib/unifi/data/keystore -storepass aircontrolenterprise -srcstorepass aircontrolenterprise
service unifi start

Now run crontab -e and edit your crontab to include the following lines:

0 0 * * * bash /opt/le-renew.sh >/dev/null 2>&1

Consider yourself done! Pat yourself on your back.