-
-
Save hisnameisjimmy/56f9414076ca39a79bfa07eefa89759e to your computer and use it in GitHub Desktop.
#!/bin/sh | |
# | |
# This script stands on the shoulders of giants. | |
# | |
# You can always find the most recent version here: https://gist.github.com/hisnameisjimmy/56f9414076ca39a79bfa07eefa89759e | |
# | |
# It is written and tested for Ubuntu 16.04 on Digital Ocean using a 1GB droplet. | |
# Anything less than 1GB of memory may cause issues with anything memory intensive | |
# like imports/exports. | |
# | |
# It does the following: | |
# 1) Opens the appropriate ports for Unifi, SSH, Web/SSL traffic via iptables | |
# 2) Makes the Unifi/Certbot software available as a package | |
# 3) Installs haveged to prevent entropy (see jeff-ferguson.com reference below) | |
# 4) Installs fail2ban as a basic security measure | |
# 5) Asks to install unattended security upgrades for long-term security | |
# 6) Uses Certbot to request a Lets Encrypt Certificate, and then installs it | |
# 7) Writes an NGINX proxy config | |
# 8) Writes out an automatic renewal cron for Lets Encrypt (as the certs expire every 3 months) | |
# | |
# I recommend running it from /opt on your server. In my installation I called it 'le-install.sh' | |
# Run it with the following: | |
# bash /opt/le-install.sh | |
# | |
# Alternatively you can make it executable and run it without specifying bash, but this is a one | |
# time script, so it seems unnecessary. | |
# | |
# Thanks to these resources below: | |
# https://community.ubnt.com/t5/UniFi-Wireless/Ubuntu-single-script-LetsEncrypt-Nginx-Proxy-UniFi-5-Repo/m-p/1626526/highlight/false#M172872 | |
# http://www.jeff-ferguson.com/2016/11/21/unifi-5-2-9-installation-script-for-digital-ocean/ | |
# https://murfy.nz/2017/01/ubiquiti-unifi-secure-installation/ | |
# | |
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, | |
# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR | |
# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | |
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | |
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE | |
# OR OTHER DEALINGS IN THE SOFTWARE. | |
# | |
RED='\033[0;31m' | |
CYAN='\033[0;36m' | |
NC='\033[0m' | |
# Gathering variables to use for the rest of the script | |
echo -en "${CYAN}Enter your domain name [my.fqdn.com]: ${NC}" | |
read NAME | |
echo -en "${CYAN}Enter your email address [[email protected]]: ${NC}" | |
read EMAIL | |
echo "These parameters are used exclusively by LetsEncrypt to register your SSL certificate and provide notifications:" | |
echo "Domain: $NAME" | |
echo "E-Mail: $EMAIL" | |
read -p "$(echo -e ${CYAN}"Does this look OK? [Y/N]: "${NC})" -n 1 REPLY | |
echo # (optional) move to a new line | |
if [[ ! $REPLY =~ ^[Yy]$ ]] | |
then | |
echo -e "${RED}Please re-run $0 and re-enter the params.${NC}" | |
exit 1 | |
fi | |
# Installing UNIFI software | |
echo -e "${CYAN}Installing Unifi${NC}" | |
echo 'deb http://www.ubnt.com/downloads/unifi/debian stable ubiquiti' | sudo tee /etc/apt/sources.list.d/100-ubnt-unifi.list | |
echo y | apt-key adv --keyserver keyserver.ubuntu.com --recv 06E85760C0A52C50 | |
echo y | apt-get update | |
echo y | apt-get install unifi | |
# iptables config | |
echo "${CYAN}Opening relevant ports via iptables${NC}" | |
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT | |
iptables -A INPUT -p tcp --dport 22 -j ACCEPT | |
iptables -I INPUT 1 -i lo -j ACCEPT | |
iptables -A INPUT -p tcp --dport 80 -j ACCEPT | |
iptables -A INPUT -p tcp --dport 443 -j ACCEPT | |
iptables -A INPUT -p udp --dport 3478 -j ACCEPT | |
iptables -A INPUT -p tcp --dport 6787 -j ACCEPT | |
iptables -A INPUT -p tcp --dport 8081 -j ACCEPT | |
iptables -A INPUT -p tcp --dport 8080 -j ACCEPT | |
iptables -A INPUT -p tcp --dport 8443 -j ACCEPT | |
iptables -A INPUT -p tcp --dport 8880 -j ACCEPT | |
iptables -A INPUT -p tcp --dport 8843 -j ACCEPT | |
iptables -A INPUT -p tcp --dport 27117 -j ACCEPT | |
iptables -A INPUT -j DROP | |
# Install relevant packages | |
echo -e "${CYAN}Updating and installing relevant packages${NC}" | |
echo y | apt-get upgrade | |
apt-get -f install | |
echo y | apt-get install software-properties-common | |
echo y | add-apt-repository ppa:certbot/certbot | |
apt-get update | |
echo y | apt-get install nginx certbot haveged iptables-persistent fail2ban unattended-upgrades openjdk-8-jre-headless | |
# Install unattended upgrades (much better long-term security) | |
read -p "$(echo -e ${CYAN}"Enable unattended upgrades for this server (with auto-reboots)? [Y/N]: "${NC})" -n 1 REPLY | |
echo # (optional) move to a new line | |
if [[ ! $REPLY =~ ^[Yy]$ ]] | |
then | |
echo -e "${RED}No security updates will be auto-installed${NC}" | |
else | |
dpkg-reconfigure --priority=low unattended-upgrades | |
sed -i.bak 's#// Unattended-Upgrade::Automatic-Reboot "false";#Unattended-Upgrade::Automatic-Reboot "true";#' /etc/apt/apt.conf.d/50unattended-upgrades | |
fi | |
# Lets Encrypt certificate request, run it non-interactively (-n) so we don't have to agree to anything | |
echo -e "${CYAN}Requesting Certificate for $NAME${NC}" | |
service nginx stop | |
certbot -n certonly -d $NAME --standalone --agree-tos --preferred-challenges http-01 --email $EMAIL | |
service nginx start | |
echo -e "${CYAN}Adding certificate to UniFi Controller for $NAME${NC}" | |
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 | |
echo -e "${CYAN}Writing nginx proxy configuration${NC}" | |
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 | |
# Automatic LE Certificate renewals - This creates a crontab for you | |
echo -e "${CYAN}Writing Crontab for LetsEncrypt renewals to /etc/cron.monthly/le-unifi-renew${NC}" | |
echo -e "#!/bin/sh\n\ | |
service nginx stop\n\ | |
echo y | certbot renew --standalone --preferred-challenges http-01\n\ | |
service nginx start\n\ | |
service unifi stop\n\ | |
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\n\ | |
echo y | keytool -importkeystore -srckeystore /etc/letsencrypt/live/$NAME/keys.p12 -srcstoretype pkcs12 -destkeystore /usr/lib/unifi/data/keystore -storepass aircontrolenterprise -srcstorepass aircontrolenterprise\n\ | |
service unifi start\n\ | |
" > /etc/cron.monthly/le-unifi-renew | |
chmod +x /etc/cron.monthly/le-unifi-renew | |
echo -e "${CYAN}\n\n\n\nINSTALLATION COMPLETE! \nYou may see a bad gateway error on https://$NAME/\nWhile the controller performs its first-time initialization\n${NC}" | |
echo -e "${CYAN}If the bad gateway persists for longer than a couple minutes, try restarting the unifi controller from the commandline${NC}" | |
The cronjob needs to have the --preferred-challenges
flag instead of --standalone-supported-challenges
.
The correct flag is used on the initial creation of the certificate.
@stevenhorner & @Theolodewijk - Thanks for the heads up on this (although, unfortunately, I hadn't looked at this script in quite a while and didn't see these comments, perhaps time to look at my notification settings). This is now fixed in the latest version.
@kelsotodd Thank you for pointing this out, I went ahead and fixed this.
Hi there, I get a kernel error: "Kernel version not supported This version of the GNU libc requires kernel version 3.2 or later. Older versions might work but are not officially supported. Please consider upgrading your kernel"
Hi there, I get a kernel error: "Kernel version not supported This version of the GNU libc requires kernel version 3.2 or later. Older versions might work but are not officially supported. Please consider upgrading your kernel" (It's a 1GB ram VPS)
@ikrudolf Where are you deploying this? I’ve only tested on Digital Ocean with Ubuntu 16.04.
Thanks for this script, it worked great on an OVH VPS running Ubuntu 16.04.
I would suggest decapitalising the domain and email as I stuffed up by putting a capital in the domain and then the domain won't exist when you add the key file because lets encrypt decapitalises it. For example, if I enter MyDomain.com lets encrypt creates /etc/letsencrypt/live/mydomain.com/privkey.pem but your script tries /etc/letsencrypt/live/MyDomain.com/privkey.pem which fails because I am stupid.
I would add:
read name
NAME="${name,,}"
and
read email
EMAIL="${email,,}"
Also:
iptables -A INPUT -p tcp --dport 27117 -j ACCEPT
is a super bad thing to have there as that is the mongoDB port on the internet. I don't believe you need it as the port is only used for loopback connections. If you really want to keep it then perhaps change it to:
iptables -A INPUT -p tcp --dport 27117 -i lo -j ACCEPT
to allow connections only from the local interface.
Realistically I would drop it back to the bare minimum of ports in the gray box here:
https://help.ubnt.com/hc/en-us/articles/218506997-UniFi-Ports-Used
Thanks for the script, it saved a lot of time.
Works great but when I try to connect my Android device to the guest portal using the secure portal and redirect using the hostname, I get the error that "The network you're trying to join has security issues." This is only happening on Android. Windows PC an Laptop works fine.
Hi there, the script works great but I can't load the site just keeps getting 502 Bad Gateway even after restarting unifi service. Just to add that I'm running Ubuntu 16.04 with 256MB of RAM.
@javidotpro 256mb is way too low for the cloud controller. You need at least 1GB, you can get away with 512MB but 1GB is recommended.
Getting an invalid certificate error in Chrome/Safari:
https://www.dropbox.com/s/9w2q8xmoekhj201/Screenshot%202018-08-01%2017.21.14.png?dl=0
Looks like it's still using the self signed cert.
I received the same Syntax error at the end of the script but did appear to work:
./le-install.sh: 169: ./le-install.sh: Syntax error: Unterminated quoted string