I have seen many people ask about settings up SSL support for HomeAssistant. It was mentioned that someone should write up a guide on how this should be done. I am by no means an expert with NGINX or SSL, but I have managed to get a working config with grade A SSL from https://www.ssllabs.com/ssltest/. Below are the steps I took to get setup with an NGINX SSL proxy using a Let’s Encrypt cert on Ubuntu 14.04, your results may very.
Step 1 - Install NGINX
sudo apt-get install nginx
Make it run at boot
sudo update-rc.d nginx defaults
At this point NGINX should be running and you can check by visiting YOUR_IP
Step 2 - Obtain your SSL cert
I will show the steps I took to use Let’s Encrypt certs, but if you want to use a self-signed cert look here https://www.digitalocean.com/community/tutorials/how-to-create-a-ssl-certificate-on-apache-for-ubuntu-14-04 (Start at step 2)
git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt/
./letsencrypt-auto --server \ https://acme-v01.api.letsencrypt.org/directory --help
Once downloaded, you will need to get your cert, run the below and follow the promts
./letsencrypt-auto certonly --standalone
After running, letsencrypt-auto will display the location of the created .pem files. /etc/letsencrypt/live/YOUR_DOMAIN/
Step 3 - Configure NGINX
*Not sure if this is required
Change the permissions on the YOUR_DOMAIN folder and it’s content by default they can’t only be access by root
sudo chmod -R 744 /etc/letsencrypt/live/YOUR_DOMOAIN/
Generate stronger Diffie Hellman Ephemeral parameter
cd /etc/ssl/certs
sudo openssl dhparam -out dhparam.pem 4096
NGINX config
I am using the default sites-enabled file under /etc/nginx/sites-enabled/ not sure if this is the proper way, but it works.
Replace test.com with your host.domain
[code]server {
listen 80;
server_name test.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
server_name test.com;
ssl on;
# For self signed certs
# ssl_certificate /etc/nginx/cert.crt;
# ssl_certificate_key /etc/nginx/cert.key;
# For Let's Encrypt certs
ssl_certificate /etc/letsencrypt/live/test.com/fullchain.pem; # /etc/nginx/cert.crt;
ssl_certificate_key /etc/letsencrypt/live/test.com/privkey.pem; # /etc/nginx/cert.key;
# Things for better security
ssl_session_cache shared:SSL:10m;
# I am using all modern devices and browsers and don't need TLSv1 if you need it, add to the list below
ssl_protocols TLSv1.1 TLSv1.2;
ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
# For quicker streaming updates in HA. Thanks @stephenmg12
proxy_buffering off;
location / {
proxy_pass http://localhost:8123;
}
} [/code]
Step 4 - When it comes time to renew your cert
Update letsencrypt
cd letsencrypt/
git fetch
Stop the NGINX service
sudo service nginx stop
Test/dry run for the renewal
./letsencrypt-auto renew --dry-run --agree-tos --email [YOUR_EMAIL]
You should get the below message
“Congratulations, all renewals succeeded. The following certs have been renewed”
Actually do the renew this time
./letsencrypt-auto renew --agree-tos --email [YOUR_EMAIL]
You should get the below message
“Congratulations, all renewals succeeded. The following certs have been renewed”
Start NGINX. For some reason I had to restart NGINX a few times before the update cert was displayed in my browser.
Make sure it all works
At this point you should be able to restart NGINX and access it from test.com which is really redirecting to your ha host at port 8123
If you are able to access it externally, try running the ssllabs tool above on your site and you should receive a letter ranking of A unless you use a self-signed cert in which case you will receive a T but it will state “If cert was trusted, your grade would have been X”
@nkgilley noticed an issue when using SSL and entity_pictures from an http site where Chrome (maybe all browsers) would state “Your connection to this site is private, but someone on the network might be able to change the look of the page.” This is because the image is getting pulled from an non-secure site. To fix this, either access the site from https or use local images.
Again, I am no expert when it comes to NGINX or SSL so if anyone has any suggestions for improvement please let me know.