Setting up nginx and SSL for Home Assistant
As part of my home automation kick, I had decided to set up a “login” for my Home Assistant over SSL/TLS, so I could have a secure, reliable connection to my server at all times. With the help of a friend, I was able to use nginx and Let’s Encrypt to accomplish these goals. Although my focus in this post will be on setting up the proxy for Home Assistant on a Pi, it could probably be generalized to other servers as well.
Prerequisites (that I can’t really help with)
The very first thing you should do is ensure that your router properly forwards requests to your Home Assistant instance. The steps for this process will vary per router, but essentially you’ll want to find a tab named “Port Forwarding” and set it up to forward requests received on port 8123 (later we’ll need to add ports 80 and 443 as well, so you can add those if you want; for debugging purposes, this is a good start). The protocol you should specify is TCP. Once that is done, get your public IP address (ie. type “what is my IP” in a search engine), and try to connect to it followed by the port 8123 (e.g. 1234.567.890:8123). It should take you to your server. If not, ensure Home Assistant is properly started and that your router is forwarding correctly.
Next, it would be nice if we didn’t HAVE to memorize our IP (or magically know if your ISP changed it), so we will register a domain to point at instead. Again, the steps for this vary per registrar, but you want to find a “domain registrar” for a website you want to use, and then create an “A Record” pointed at your WAN IP from earlier. You can typically specify subdomains here too if you want to, or just use “@” for the host if you want to connect directly (e.g. via “example.com”). Once that’s saved, you should be able to connect to your site followed by the port 8123 (e.g. “example.com:8123”) to hit your server.
Bear in mind that as your IP changes, you may need to update your “A” Record. Some registrars have APIs you can hit, and some routers allow you to configure “Dynamic DNS” entries yourself. Be sure to set something up, as otherwise you may try accessing your site one day and find out it goes nowhere.
Setting up authentication with a reverse proxy
Our setup so far is good, but what would really be nice is some authentication to control access to our server. nginx can help us with this.
The first step is to install nginx as well as the apache2-utils we’ll be using later:
If you want to research the general nginx settings and configure them in /etc/nginx/nginx.conf, now would be the time. Otherwise, I’ll continue with the specific ones for our server in a bit.
Next we will set up the login for our server. To do this we run the htpasswd util we fetched earlier, and invoke it with:
It should then prompt you for a password, which will complete your credentials process. You can use a different path if you want (and even a different file name), I will just assume that is the location for this tutorial.
At this point you have two options. If you have no plans to use SSL and simply want authorization, then you can stop after completing this section. If you want SSL (and only SSL), then you’ll have a different configuration that I’ll detail in the next section. Either way, since we need to set up Let’s Encrypt too, we may as well follow the plain HTTP route to ensure everything works as intended.
Edit your /etc/nginx/sites-enabled/default file to redirect requests received on port 80 to 8123:
You can start the server with sudo service nginx start. If you haven’t already, set up port forwarding on your router for port 80 (and 443 if you plan to set up SSL) to point at your nginx server as we did before with port 8123. If this step went well, then you should be able to connect to your site (without any port, e.g. “example.com”), and be prompted with a login. Upon success, it should redirect you to Home Assistant.
Finally, we want the nginx service to start on boot, so we can configure systemctl to do so. Run:
then input something like these instructions.
Finally you’ll need to enable it:
Now if you reboot your machine, your nginx server should automatically start up.
Just a couple weeks ago, EFF came out with a nice update to its Let’s Encrypt client called “certbot” that has simple instructions to create certs for your website. For completion’s sake I will include the steps I followed, but I would highly recommend checking out the site if you need more info.
The first step here is to add backports to our apt-get sources list. If you’re running a Pi 3 on Jessie, you can do this via:
Then run an update and install the client:
Finally, you can run the client by calling:
and following the instructions on the screen (I’m running a standalone server which is option 2 from the initial list). When it’s done, you should see a message specifying the path to your keys. Take note of those as we’ll need them in a bit. In the meantime, you should add a cron job to update your keys, as they expire after 90 days. The EFF suggests twice daily updating on “random” minutes, so we can do something like:
Now go back to your nginx configuration (/etc/nginx/sites-enabled/default) and make your requests go over SSL/TLS. Be sure to replace “example.com” with your site:
Restart the nginx service with sudo service nginx restart and try to hit your site again. If everything went well, then any requests to (for instance) “http://example.com” should be redirected to “https://example.com”, prompted with a login, and finally redirect to your Home Assistant server. Now you have a secure server to monitor your home automation site any time you want!
One thought on “Setting up nginx and SSL for Home Assistant”
You’re line with the ssl_ciphers is cut off causing mass confusion when trying to get a valid config. Thanks for the tutorial.
Thanks for the heads up, Brian. I believe it should be fixed now!
Hey Igor, thanks for Your article!
I suggest adding these headers, if someone’s having an error message “Connection lost. Reconnecting…”.
It will fix web socket connection problem.
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection “upgrade”;
Have a great day! 🙂
Thanks Martin, updated (properly, I think). I may have even added those to my local config at some point and just forgotten to update my post.
I was wondering isn’t there a way where home assist talks to a small script on a webserver or aws and basically gets the readings of all the sensors attached and switches etc. And when you say turn off the light on the app it basically tells the sever script to send a mqtt message to the home assistant. Why is this so complicated? Sorry this may be a noob comment.