Introducing tunnel based remote access for Home Assistant
Tags: showdev, tips, tutorial
Published: 2019-01-27 11:41:39

---
title: Introducing tunnel based remote access for Home Assistant
published: true
description: Secure reverse tunnels for Home Assistant
tags: showdev, meta, tips, tutorial 
cover_image: https://thepracticaldev.s3.amazonaws.com/i/pyvv1row4q0zcxrlilbm.jpg
---


First things first, what is Home Assistant? [Home Assistant](https://www.home-assistant.io/) is an automation hub that allows you to easily deploy and interconnect a large number of different apps/services/hardware gadgets together. It can accept webhooks, launch tasks or run more powerful workflow engines such as Node-RED inside it (as an add-on). It's a fantastic thing to have installed on your spare Raspberry Pi (I know you have one 😏).

Home Assistant GitHub repo (https://github.com/home-assistant/home-assistant) has 20K stars which probably is a good testament for its popularity :) 

In this short article I will present you my add-on, which uses [Webhook Relay](https://webhookrelay.com/) cloud service to provide an easy and secure remote access to a Home Assistant running on RPI:

![Remote access home assistant addon](https://thepracticaldev.s3.amazonaws.com/i/8ep723h2fjfathq1xf54.png)

It might look like a lot of different tools, but most of it is automated and doesn't require any complex configuration.

**If you just want to try it out, skip to the 'Trying it out' section**

---

## So, why remote access add-on?

Since Home Assistant is usually deployed in your local network, connecting to it from outside can be problematic, unless you configure your router to do the port forwarding. However, there are cases when it's just not possible:

- ISP is blocking inbound connections - simple, no port forwarding will help here. 
- Double NAT due to 4G networks - same as above.
- Can't access/configure the router
- No static IP
- Server that is hosting Home Assistant is changing location/IP address
- Router doesn't support port forwarding

The add-on works by creating a tunnel back to the cloud service and allowing any outside traffic (from your phone on 4G or your office network) ride back to the Home Assistant on top of that previously established tunnel. This way no incoming connections to the server require port forwarding or static IP. 

## The add-on 

The add-on is a lightweight daemon, it's based on the [webhookrelayd Docker image](https://hub.docker.com/r/webhookrelay/webhookrelayd-aarch64/tags) and its size is just 5MB. The application is written in Golang, this makes it fast and efficient. It barely uses any RAM or CPU. This application is tailored to consume Home Assistant add-on configuration JSON files and treats it as a first-class citizen, no dirty shell script hacks (like many other add-ons) involved to consume that config.

## Security & Privacy

One of the first thing that I had to develop for Webhook Relay for this add-on to succeed was TLS pass-through tunnels. Several main developers of Home Assistant said that TLS termination on the user device is crucial to make it secure. Not even Home Assistant Cloud does this for the webhooks, they terminate TLS on their cloud services and then pass it on to the users. So, I had to look at 3rd party services that would provide free subdomains + support Let's Encrypt. Gladly, [DuckDNS](https://www.duckdns.org/) saved the day :) 

As for TLS pass-through & termination, Golang has a great standard library to deal with this, it's just reversed (normally you would be terminating incoming connections to your server as opposed to terminating outgoing connections from the server). 


## Putting it all together

Once the add-on starts, it reads the configuration and ensures tunnels in Webhook Relay. These tunnels are just a routing configuration, that tells cloud service to direct requests from `example.duckdns.org` to `client-xxx`. It then configures DuckDNS A record `example.duckdns.org` to an IP address that belongs to Webhook Relay and also retrieves HTTPS certificate from [Let's Encrypt](https://letsencrypt.org/) using DNS challenge (since we don't have HTTP traffic to the client yet). Having that certificate, we can set up TLS termination on the client side. Home Assistant is still called on HTTP port through `http://localhost:8123` while all the external traffic is fully encrypted. 

## Trying it out

Before we begin, this tutorial will expect you to have:

* **Basic** plan subscription ($4.5/m) which enables DuckDNS domains and TLS pass-through tunnels. If you don't want to commit, drop us an email at info@webhookrelay.com and we will set up a 2 weeks trial for you.
* [DuckDNS](https://www.duckdns.org/) account to get your own free domain and retrieve TLS certificate through [Let's Encrypt](https://letsencrypt.org/).

Configure DuckDNS:

![DuckDNS config](https://thepracticaldev.s3.amazonaws.com/i/hbrj6h7a8zxmfug4tpo8.png)

Installation of this add-on is pretty straightforward and not different in comparison to installing any other [Hass.io](https://hass.io) add-on:

  1. Add our Hass.io add-ons repository URL to your Hass.io instance: https://github.com/webhookrelay/home-assistant
  2. Install the “Webhook Relay” add-on
  3. Generate a [token key & secret pair](https://my.webhookrelay.com/tokens) and add it to the add-on configuration
  4. Get [DuckDNS](https://www.duckdns.org/) token and create your domain. Add those details to the "tunnels" config section and "duck_dns" section. Set "accept_terms" to true if you accept [Let's Encrypt ToS](https://community.letsencrypt.org/tos)
  6. Start the “Webhook Relay” add-on
  7. Check the logs of the “Webhook Relay” add-on to see if everything went well. It should print out your public URL

Configuration example:


```json
{
	"key": "[YOUR WEBHOOKRELAY KEY]",
	"secret": "[YOUR WEBHOOKRELAY SECRET]",
	"forwarding": [],
	"tunnels": [
		{
			"name": "ha",
			"destination": "http://127.0.0.1:8123",
			"protocol": "tls",			
			"domain": "[YOUR SUBDOMAIN].duckdns.org"			
		}	
	],
	"duck_dns": {
		"token": "[YOUR DUCKDNS TOKEN]",
		"accept_terms": true
	},
	"tunnels_enabled": true,
	"forwarding_enabled": false
}
```


That's it, you should be able to access your Home Assistant through your domain that you have configured, in my case it's https://auto-ha.duckdns.org. We have got full, end-to-end encryption without configuring your router or getting a static IP:

![HA](https://thepracticaldev.s3.amazonaws.com/i/8bcm6xtzinfy8rzt20up.png)

Also, instead of using DuckDNS & Let's Encrypt, you can use any certificate you want or just don't supply any certs to the add-on and terminate TLS on Home Assistant server. For that you will just have to specify HTTPS in the destination: `"destination": "https://127.0.0.1:8123"`. Add-on TLS termination is purely just to make your life easier, why do it manually when you can automate it? 

## Troubleshooting

**DNS issues**

As with any systems that let you tinker a lot, there can be issues. I have noticed that running [pi-hole](https://pi-hole.net/) on my Raspberry Pi often breaks DNS and containers can no longer access the internet. Restarting helps but you might want to look for a more permanent solution by modifying (https://github.com/home-assistant/hassio/issues/497). 

If you are using hassio provided image, then the procedure of fixing DNS in Docker is a bit more involved, check their debug [documentation](https://developers.home-assistant.io/docs/en/hassio_debugging.html)

**Multiple tunnels & IP addresses**

In the example above, you can modify tunnel configuration to have multiple tunnels

```
"tunnels": [
		{
			"name": "ha",
			"destination": "http://127.0.0.1:8123",
			"protocol": "tls",			
			"domain": "[YOUR SUBDOMAIN].duckdns.org"			
		},
                {
			"name": "node-red",
			"destination": "http://127.0.0.1:1880",
			"protocol": "tls",			
			"domain": "[YOUR NODE RED SUBDOMAIN].duckdns.org"			
		}	
	],
```

You can set the IP address to some other local network address such as http://192.168.1.120:1880 if that's where your Node-RED or some other service is running. 


**Custom domains or no domains**

You can always use `*.webrelay.io` subdomains as they are provided with tunnels by default. Just set the protocol to 'https'. 
Another option is to use your own domains and certificates, check [configuration examples(https://www.home-assistant.io/docs/ecosystem/certificates/tls_self_signed_certificate/). Once you have HTTPS on your Home Assistant, specify your domain and change destination to https: `"destination": "https://127.0.0.1:8123",`. Don't forget to create a CNAME record to your Webhook Relay tunnel (should show up in the [tunnels page](https://my.webhookrelay.com/tunnels)

Thanks for reading!