Encrypt the Home


I find there is far too much tedium in life, and, as any good nerd does, I try to automate the boring stuff out of my life. For day-to-day tasks around the house, such as forgetting to turn off the lights when leaving a room (I always got in trouble for that as a kid), I turned to home automation with Home Assistant acting as the master controller. Home Assistant is an open-source home automation platform that works with almost every possible smart home device through either direct integrations or community Apps. It has had a lot of improvements and new features over the years with lots of updates to the UI making it easier to get started. There are many guides out there from many popular YouTubers that go into all the details about getting started.

Since Home Assistant ends up connecting to various cloud accounts as part of some of the integrations, a username and password often have to be entered into the web UI. Home Assistant defaults to running on HTTP port 8123. While running on a local home network is probably safe under the assumption that the network is free from other devices trying to capture traffic, upgrading to HTTPS adds an extra layer of security. There is no quick configuration option to flip a switch and enable HTTPS with a self-signed certificate, as some other web services have. Not to mention, using a self-signed certificate will throw browser security warnings the first time you visit the URL after each browser restart.

Let’s Encrypt the connection

Let’s Encrypt is a free, automatable service that provides valid certificates for your domain to enable SSL connections over HTTPS without browser warnings and with a verified checkmark in the address bar. I’ve been using Let’s Encrypt over the years through the SWAG LinuxServer Docker container, which combines an NGINX reverse proxy server with automated Let’s Encrypt certificate renewals and offers many example configurations for various services. Enabling HTTPS for Home Assistant can be done using the same basic process with official Apps. I run Home Assistant OS on a Home Assistant Yellow, so your steps might be different if you are running it on Docker (if you are using Docker, I suggest using the SWAG Docker container as the front end with Docker networking to enable HTTPS).

Safety First

Before making changes to how the web UI is accessed, I wanted to make sure that I would have an alternative access point to make any necessary changes if I made a mistake and locked myself out (spoiler alert, that happened). Using another official App, Terminal & SSH, I set up SSH access by installing the App and enabling both the Watchdog and Start on boot. In the configuration tab, I added an SSH public key for passwordless login. After adding the necessary configuration to my local SSH config (with the host, root user, and the identity file of the private key), I tested the SSH access and left the session logged in while making changes. I like to use VS Code for remote SSH file access as it provides an integrated terminal and file editor.

SSL Certificate Generation

Getting the SSL certificate from Let’s Encrypt requires performing a challenge to verify that you have control over the domain (I forgot to mention: you need to have a domain, or at least that is how I have always done this, using a purchased domain). For my challenge, I will be using DNS via Cloudflare and obtaining a wildcard certificate. A wildcard certificate allows for any and all subdomains (e.g., www, homeassistant, or ha) under one certificate.

  • Install the Let’s Encrypt App on Home Assistant.
  • Add your domain (e.g., *.blackeyetoad.com).
  • Add your email.
  • Leave the key and certificate filenames as they are:
    • privkey.pem
    • fullchain.pem
  • Set the challenge type to dns.
  • Under the DNS dropdown, add your API key:
    • cloudflare_api_token: [YOURTOKENHERE]

YAML:

email: [email protected]
domains:
  - ha.domain.com # or *.domain.com
certfile: fullchain.pem
keyfile: privkey.pem
challenge: dns
dns:
  provider: dns-cloudflare
  cloudflare_api_token: [REDACTED_API_TOKEN]

The resulting certificates are stored in the /ssl/ directory.

Starting the App should result in Certbot running, obtaining your certificate, and installing it as specified.

Proxy the connection for SSL

Now that the SSL certificate has been issued and installed on your HA machine, we can set up NGINX as the front end to allow a secure connection. The HTTPS connection will go from your browser or app, terminate at the proxy server, and then be handed over to the standard HTTP port internally on the HA machine. This means your communication to and from the UI is now encrypted for all but the last leg, which is run entirely on the machine’s localhost.

  • Install the NGINX Home Assistant SSL Proxy App.
  • Enable Start on boot and Watchdog.
  • In the configuration tab:
    • Set the URL you will be accessing to ha.domain.com.

YAML:

domain: ha.domain.com
certfile: fullchain.pem
keyfile: privkey.pem
hsts: max-age=31536000; includeSubDomains

Start the App, and it should now proxy incoming HTTPS traffic—or at least it will once you set up the DNS entry on your local network to point ha.domain.com to 192.168.1.200 (your Home Assistant IP address).

Extra Hardening

Since it has been a while since I set up the proxy, I may have missed a few steps or minor troubleshooting details, but everything detailed above is from my Obsidian notes. I also took a few extra steps to block access to the original insecure HTTP port. This also forces me to fix any previous connections such as the companion app and use the new secure URL.

Changes in /config/configuration.yaml:

YAML:

http:
  # Limits listening to the internal Docker gateway only
  server_host: 172.30.32.1 
  # Allows NGINX to pass the user's real IP to HA
  use_x_forwarded_for: true 
  # Trusts the internal network range for Apps
  trusted_proxies:
    - 172.30.33.0/24
    - 172.30.32.0/24

This completely locks down the original insecure UI access. Unfortunately, this caused me to lose access to the UI after a restart because I initially configured the wrong IP in the trusted_proxies section. Luckily, I was able to use the SSH access that was set up at the beginning to make the modifications and get it working correctly.

This setup has been working on my local Home Assistant for a few months now, allowing secure UI access.

Certificate Renewals

Since this is running on Home Assistant, which is all about automation, I added an automation to ensure the certificate never expires and that the dreaded browser security warning doesn’t pop up.

alias: Weekly Let's Encrypt Renewal
triggers:
  - at: "03:00:00"
    trigger: time
conditions:
  - condition: time
    weekday:
      - sun
actions:
  - data:
      addon: core_letsencrypt
    action: hassio.addon_start

This automation will start up the App running Certbot to determine if the certificate is expiring soon, renew it if necessary, and exit afterward.