Originally posted 2018-06-05 15:35:04.
Lets 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-on | Port |
---|---|
Configurator | 3218 |
Terminal | 7681 |
SonWEB | 9541 |
Home Assistant Itself | 8123 |
SSL Certificate Renewal | 80 |
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
- 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.
- On my Router, I removed ALL the port forwarding except for port 80, 443 and 8123
- 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.
- 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.
- 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. - 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)
- You will need to add this repository to the add-on store in the Hassio panel:
https://github.com/korylprince/hassio-caddy
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.
- 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. - 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. - 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 thehttp:// 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 usehttp:// 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.
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?
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….
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 🙂
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.