Setting Home Assistant up for Secure access over the Internet



Originally posted 2018-06-05 15:35:04.

Phishing Remove MalwareLets have a conversation about security when your Home Assistant is opened up so you can access it over the Internet.

If you take a look over on the Home Assistant Community forums here there are threads about user’s home assistant instances being hacked with ‘friendly’ hackers who have just changed a few things and left some warnings about their insecure home assistant setups.

Traditionally or ‘normally’ external access to your system over the internet means that you would open up some ports on your router so that you can connect over the internet. This would typically mean that you would forward the required ports to your Raspberry Pi that is running home assistant. Some people get quite lazy with this and might even put the IP address of their Raspberry Pi in the DMZ (DE-militarised-zone) or their router which totally exposes it to the internet. This total exposure is pretty much the worst thing you can do if you care about security. The other option commonly is to just forward specific ports. Unfortunately, a lot of people that do this don’t use any password much less a secure password and their systems are sitting ducks for the bots and hackers which do scan IP addresses systematically trying to find and exploit insecure systems. This is destined to not ever end well.

My Home Assistant Configuration

With my Home Assistant, I am using several add-ons that I like to be able to access when I am on the go out of the office. For some reason I always seem to want to be able to edit my files or update the system when I’m traveling. I also like to be able to switch on my coffee maker when I am on the way home or I like to use Google Assistant for the same purpose if I am traveling in my car.

I currently use the following add-ons. The add-on and port number they ‘listen’ on are in the following table:

Add-onPort
Configurator3218
Terminal7681
SonWEB9541
Home Assistant Itself8123
SSL Certificate Renewal80

So that is 5 ports I would have forwarded on my router. This is 5 potential vectors of attack on my system if a hacker was to scan those ports on my IP address. Of course they are protected by usernames and strong passwords. These are not uncommon add-ons used with Home Assistant. Certainly Configurator and Terminal are very common. SonWEB is a management tool for Sonoff devices and can be used for example to update firmware and manage sonoff devices in a nice user interface.

It is also common to use these add-ons via the front end of Home Assistant in an iFrame. If you did not want to use these in an iFrame or over the internet then you could just access the add-on via the IP address and port locally. For instance, if the IP address of your Raspberry Pi is 192.168.1.25 to access the Terminal, you could type this into a web browser:

http:// 192.168.1.25:7681

All good….. but it’s more convenient and less restrictive to just access it through Home Assistant itself by configuring it in an iFrame. The other thing is that if you want to access Home Assistant over the internet, you really need to use an SSL certificate so that your communications over the internet are encrypted and your username and password remain secure. In addition, to use SSL you really will need a domain name (like a free one provided via duckdns) so that your Home Assistant can be found by you when you are trying to connect. Because of this, you will normally access your home assistant internally and externally using a URL that looks like this:

https:// my-domain.duckdns.org:8123  perhaps without the port.

Doing this precludes using the local IP address in an iFrame so normally, you’d forward the ports as above and configure the iFrame so you can access your add-ons easily from Home Assistant.

In truth, there is probably not a huge risk in doing this. Most port scanners will only scan the first 1024 ports and with the exception of port 80 they are way above that. Also if you use a username and strong password (say 16 or greater characters, upper/lower case, numbers and a special character) it’s low risk. Configurator also has a ‘sesame’ password that is used to whitelist the connecting IP address so it’s pretty secure. Port 80 is only used for renewing the SSL certificate. It is normally closed unless the LetsEncrypt SSL certificate is being renewed.

I have also seen numerous discussions about using NGNIX and reverse proxies but these seem to be unintuitive and complicated to me. I recently became aware of an easier to implement and understand proxy called Caddy. At this point I need to give a big thank you to a user on the Home Assistant Community forum and also in the Discord Support chat @cogneato who gave me every assistance in getting this working.

Steps to Install Caddy

By default, Caddy will bind to ports 80 and 443 to serve HTTPS and redirect HTTP to HTTPS.

To install Caddy, follow these steps:

 

  
  

Note: You need to install the repository into Home Assistant. See step 7 below for how to do that.

You will then see the Caddy Web Server and you can

  1. If you have SSL already installed, you need to disable it. Caddy will obtain it’s own SSL certificates. In my case, I just disabled (and after everything was running) removed the SSL add-on. If you are using a combined DuckDNS and LetsEncrypt add-on you will have to disable the SSL part. (For clarity, to disable SSL if you are using the DuckDNS addon – just set accept terms to false in the addon configuration. It actually doesn’t matter anyway as Caddy will get it’s own certificates and manage them itself.) The DuckDNS is still needed. On my system, my router handles the DuckDNS configuration and updating.
  2. On my Router, I removed ALL the port forwarding except for port 80, 443 and 8123
  3. in your configuration.yaml file, comment out the ssl references in the html section viz:
    http:
      # Uncomment this to add a password (recommended!)
      # api_password: !secret http_password
      # ssl_certificate: /ssl/fullchain.pem
      # ssl_key: /ssl/privkey.pem
      use_x_forwarded_for: true
      trusted_proxies:
        - 127.0.0.1
        - ::1
      # trusted_networks:
      #   - !secret trusted_network
      ip_ban_enabled: True
      login_attempts_threshold: 5
      # Uncomment this if you are using SSL/TLS, running in Docker container, etc.
      base_url: https:// my-duck-dns-domain.duckdns.org:8123
    

    Note I have edited this post on 10th Jan 2019 as I was finding that I was getting my IP banned every couple of days so I started using x_forwarded_for and trusted_proxies. Doing that reveals the real IP address of anything connecting via a proxy (which is what Caddy is). I also removed trusted networks and the api_password as I am using HA Auth with 2FA and it keeps me logged in as I store the login. Also, any hacker entering an incorrect password is locked out after 5 attempts stopping brute force attacks. Additionally, in order to use the webhooks and the IFTTT integration, the base_url needs to be defined so that is there as well.

  4. Any add-ons for Home Assistant should have SSL set to FALSE and the iFrame configuration for the add-ons in configuration.yaml should look something like this depending on which add-ons you use:
    #Configurator, Terminal & MDI Icon Files
    panel_iframe:
      configurator:
        title: Configurator
        icon: mdi:wrench
        url: URL for add-on
      terminal:
        title: Terminal
        icon: mdi:console
        url: URL for add-on
      sonweb:
        title: SonWEB
        icon: mdi:lightbulb-on
        url: URL for add-on
    

    The URL for these will need to be changed later but you can just leave these as is now. This will become clear when we configure Caddy.

  5. Restart Home Assistant now and you should be able to navigate to and see the Home Assistant front end without any browser warnings or errors. You should also be able to go to http:// my-domain.duckdns.org:8123 or http://  hassio.local:8123 as well without any errors or warnings. If this is all working go to the next step.
  6. You can now remove the port forwarding for port 8123 from your router. You should only have ports 80 and 443 forwarded (unless you have other non Home Assistant ports forwarded)
  7. You will need to add this repository to the add-on store in the Hassio panel:
    https://github.com/korylprince/hassio-caddy
    add-repo-to-home-assistant
    When that add-on is installed DO NOT ACTIVATE it yet. In the config section of the add-on, enter these lines:

    {
        "flags": [
            "-agree",
            "-email",
            "user@example.com"
            ]
    }

    Enter an email address instead of user@example.com LetsEncrypt needs this before it will issue a certificate.

  8. We now need to create a Caddyfile with the information about our domain and the proxy configuration. To do this you will either need to have the Samba add-on installed so you can access the file in Windows or a better choice would be WinSCP. You will need to navigate to the folder /share/caddy/ and then create and edit a text file called Caddyfile. (the caddy folder will need to be created) This file will look something like this depending on your add-ons:
    
    my-domain.duckdns.org {
        header / {
        Strict-Transport-Security "max-age=31536000; includeSubdomains"
        X-XSS-Protection "1; mode=block"
        X-Content-Type-Options "nosniff"
        X-Frame-Options "SAMEORIGIN"
        Referrer-Policy "same-origin"
    }
        proxy / localhost:8123 {
            websocket
            transparent
        }
    }
    
    terminal.my-domain.duckdns.org {
        proxy / localhost:7681 {
            websocket
            transparent
        }
    }
    
    config.my-domain.duckdns.org {
        proxy / localhost:3218 {
            websocket
            transparent
        }
    }
    
    sonweb.my-domain.duckdns.org {
        proxy / localhost:9541 {
            websocket
            transparent
        }
    }
    

    This is my configuration for the 3 add-ons I use in Home Assistant and also Home Assistant itself.

    As you can see, the add-ons are all sub-domains of the main duckdns domain.
    If you’re interested, you can do a security scan on your site here. If you use those, dont forget to specify the port! See also Shodan which will tell you which ports you are exposing. With Caddy, you should only see port 80 and if you try and connect you should get an error.

    Now that we have the Caddyfile, we can start the add-on in the Hassio panel. If all goes well and you view the log file at the bottom of the screen, you should see something like this:

    
    starting version 3.2.4
    Running Caddy with arguments: -conf /share/caddy/Caddyfile -agree -email my-email-address
    Activating privacy features... done.
    https:// my-domain.duckdns.org 
    https:// terminal.my-domain.duckdns.org 
    https:// config.my-domain.duckdns.org 
    https:// sonweb.my-domain.duckdns.org 
    http:// my-domain.duckdns.org 
    http:// terminal.my-domain.duckdns.org 
    http:// config.my-domain.duckdns.org 
    http:// sonweb.my-domain.duckdns.org
    

    If you see that, it’s all working and you should be able to access https:// my-domain.duckdns.org (without the port 8123) or http:// hassio.local:8123(with the port 8123) and see the Home Assistant frontend.

  9. Just one other thing for your consideration. I decided to use a different port number for SSL than port 443 and have removed the port forwarding in my router for 443 but have added the forwarding for port xxxxx to port 443 in my router. If you do this, you will need to use the port in the URL’s you configure in step 10 as I show below. If you are happy to use 443 (and leave that port forwarded in your router) you do not need to include the port. You will need to leave port 80 forwarded so Caddy can renew the SSL certificate and the port 443 or xxxxx as per your preference.
    It’s also worth pointing out that using a non-standard port for https connections increases security. Using port 443 is like having a house and everyone knows where the door is – but if you use a non-standard port, you are hiding the door like a needle in a haystack.
  10. You will now need to configure URL for the add-ons in the iFrame for Configurator, Terminal and SonWEB.
    #Configurator, Terminal & MDI Icon Files
    panel_iframe:
      configurator:
        title: Configurator
        icon: mdi:wrench
        url: https:// config.my-domain.duckdns.org:xxxxx/sesame-you-set-for-configurator
      terminal:
        title: Terminal
        icon: mdi:console
        url: https:// terminal.my-domain.duckdns.org:xxxxx
      sonweb:
        title: SonWEB
        icon: mdi:lightbulb-on
        url: https:// sonweb.my-domain.duckdns.org:xxxxx
    

    Where xxxxx is the port number you used as per above (otherwise omit :xxxxx). For Configurator, if you use a ‘sesame’ as added security and IP whitelisting as per the add-on documents that is added after the port as shown above. Note that xxxxx is the same for every add-on. The port being proxied is set in the Caddyfile.
    Additionally, you should also be able to use the http:// hassio.local:local-port (3218, 7681, 8123 or 9541) and access the add-in directly (not through iFrame) without any certificate errors as well as using the duckdns url’s. (you might need to use http:// hassio.local:3218/sesame-you-set-for-configurator for configurator if you get a policy not fulfilled error – after your IP address is ‘whitelisted’ it should work without the sesame)

Once again many thanks to community member @cogneato.

Google Assistant Changes

One other thing you will need to look at is Google Assistant if you are using it. In my earlier posts I went through the integration with Google Assistant. If you use Caddy as described above, you might need to make a couple of changes in Google Assistant configuration for that to continue working.

Google assistant requires an SSL connection to home assistant for the integration to work. In my case, prior to using Caddy, the URL I had entered was https:// my-domain.duckdns.org:8123/api/google_assistant/auth

As I changed the port to xxxxx I needed to edit this in the Google Developer Console.

I struggled with this and eventually found there were two different places where this needed to be changed. The first is in the Overview > Quick Setup > Setup Account Linking > Client Information > Authorization url. The second place is in the Overview > Build your Action > Add Actions > Click-on-action-in-list > Add fulfillment URL and enter the correct URL there as well. Once that is done you should test by going into the simulator again as per the original instructions. I also unlinked my account in Google Assistant on my phone and re-linked it again.

Summary and Conclusion

Just to conclude, if you install Caddy and remove all port forwarding except for port 80 and port 443 (or xxxxx) You will be able to access home assistant via any of the following:


http:// hassio.local:8123
http:// ip-address-of-ha:8123
https:// my-domain.duckdns.org (:xxxxx if non standard port)

And you will be able to access add-ons like Terminal (shown below) in a similar manner:

http:// hassio.local:7681
http:// ip-address-of-ha:7681
https:// terminal.my-domain.duckdns.org (:xxxxx if non standard port)

Note for configurator you will also need to include the sesame if you use one.

On some systems, hassio.local may not resolve correctly or at all in which case use the IP address.

If you configure an iFrame, you can choose between the duckdns url or the hassio.local one however if you use hassio.local or the ip address, you will get certificate errors when you connect over the Internet. There does not seem to be any reason to not use the duckdns address for internal and external connections. This may depend on if your router will allow this loop-back or not.

Lastly, all URL’s in this article – I have placed a space after https:// so I don’t get broken link errors.

Hopefully this is reasonable clear. Let me know in the comments below!

One other note: see my new article here as I have worked out how to use DNS validation for SSL certificates from LetsEncrypt now and this port 80 no longer needs to be forwarded.



4 thoughts on “Setting Home Assistant up for Secure access over the Internet

  • November 18, 2018 at 12:29 pm
    Permalink

    very cool. I got it working but still have one issue: now that ssl is off for my addons, I can’t use the “Open Web UI” button in Hassio. Do you know of a workaround to get that button working again?

  • November 18, 2018 at 1:29 pm
    Permalink

    No – I don’t know of any workaround for that. It’s because you are using SSL for Home Assistant but the open webui links to a local IP address. If you go to http://localip-address:8123 and then navigate to the addon and click ‘Open Web UI’ button it works.

    I also have most of the addons with a webUI setup as an iFrame using the https://subdomain.domain.duckdns.org:xxxxx and then I can just select it from the Hassio panel….

  • January 15, 2019 at 1:27 pm
    Permalink

    Hi David,
    first up, thank you for a great write up and I hope I get to implement your solution – but first can I please clarify the below, as I do have duckdns via hass.io working ok within my home network but not over 4G or outside the home network. Port forwarding on the router seems to work ok as I successfully opened port 80, 443 and 8123 for the DuckDNS setup to complete and exchange files.

    Q1: are you using the Home Assistant iOS app via your Caddy setup and is that working ok?
    Q2: should I remove DuckDNS add on (but keep the subdomain of course) before I install Caddy? In other words are the two services mutually exclusive?

    Thank you in advance!… Oh and I’m Melbourne-based so I will be keeping an eye on your experiences with local hole automation 🙂

    • January 15, 2019 at 1:37 pm
      Permalink

      Hi kostasw
      Yes I am using the iOS App and Caddy and it works fine. In actual fact, at the moment, My DuckDNS domain only has an IPv6 address (I removed the IPv4 one). You still need your duckdns domain and it needs to be updated with either/both an IPv4/IPv6 address so you do keep the DuckDNS addon. I am using a script on my NUC to keep the IPv6 address current (however it’s static and doesn’t change anyway). The only change in the DuckDNS addon would be to not get the LetsEncrypt certificate as Caddy will get it’s own certificates. (it actually probably doesn’t matter if the DuckDNS gets one as well)
      With IPv6, you don’t forward any ports but you do open a specific port(s). I have port 443 and port 80 ‘opened’ for Home Assistant. Which ISP are you with? NBN or other?
      Hope this makes sense.

Leave a Reply