Expose Home Assistant through an SSH tunnel

Expose Home Assistant through an SSH tunnel

Today I will show you how to expose your Home Assistant through an SSH tunnel, and keep it active with autossh. Then use an Nginx reverse proxy on your remote server combined with your own custom domain to use Home Assistant over the internet.

This can be used as an alternative for Port Forwarding on your router, and in case of a dynamic IP address, a Dynamic DNS provider like DuckDNS, DynDNS, ... And can even be used from inside a VM. Everything is self hosted and doesnt require any 3rd party services.

You can use all of Nginx' features on your remote machine in an industry standard way without affecting or having to configure anything on your Home Assistant. For example you can configure SSL certificates on your Nginx, and only need to encrypt that endpoint, as an SSH tunnel is encrypted by default.

Requirements

  • Raspberry Pi with Hass.io installed (version used in this blog post is 0.78.3)
    In case you are using Hassbian, you can do it manually. In any other case, im not sure what is possible.
  • A remote linux machine.
  • A custom domain

1. Install autoSSH Hass.io addon

For starters you will have to install an addon, which will install all the necessary dependencies for you. This addon is a fork of the excellent addon by odinuge. The only difference being that the host network has been exposed to the autossh container.

  1. In Home assistant go to Hass.io -> Add-on Store
  2. In the repositories at the top add my repository: https://github.com/pjcarly/hassio-addons
  3. Install the add-on HASS Tunnel
  4. Start the add-on

At this point, we start the add-on for the first time, so we can extract the public key which will be generated by the container on the first run. We need that key, to authorize our access on our remote server in the next step.

Because the add-on itself hasn't been configured yet, nothing else will happen.

Refresh your addon log (on the bottom), until you see something similar like this:

starting version 3.2.4
[INFO] Setup private key
Generating public/private rsa key pair.
Your identification has been saved in /data/ssh_keys/autossh_rsa_key.
Your public key has been saved in /data/ssh_keys/autossh_rsa_key.pub.
The key fingerprint is:
SHA256:FhxM+7e2fmQt1Qgyz6TEqoHoxcFTZytYOfnjCsMpVgU root@03351470-autossh
The key's randomart image is:
+---[RSA 4096]----+
|   .Eoo==.       |
|    +o=+.+= o    |
|   o.=.o=o B . ..|
|  . = ..+o. o . o|
| . + . +S.. .  o |
|  + = ...  . .+ .|
| . . o .    oo . |
|      .    . ..  |
|           .o.   |
+----[SHA256]-----+
[INFO] public key is:
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDZZ9V6nb+on+nuaAU1MLPPEGm+tv6RP6if3oUQx9bFNBjMuPpytjNUjhX/CZXcIf6IB+K52SYZzNL18ADBTr0oJb4Aog70QU/+LDzX3ljxGTnZBKLBgM+CsOhUgBYw5tpiSTWlBhedKd48xXvhmJ959+2md/x1qNVWXwecNrHUHquWz3CJYcUtY9A4V4PaWz7nFpcGxyWRJaMU+iHexb3Jyf7Cly/EvPxITJ9KE2CbQoRlONF3JYXkgwrjYCa91EXTYOV/S5UR2j9y8FjlYAzmGZqDMQ0G/PzIiYSC7nprl96OdzEVNXHo6NYusRfypDWhkOQi1OEnX0MusVb4Ax34UD/Yt92Kt5zBTFJ+IZJxw5izDbdBSHfngH2orwxFgF+iFAxWmLi6d71B8JdXj/72lTtUmyu4qJBOlN8RMEZOWxmrrnJZutCHZzYqeAYnN6C6rpVpGmUZKyD/FhP1YJB2gcqg87TdH0abjgbRO59g7u7zzFEG4JZeHqzSiDeh6SwWK1VWWn/9iBE3mWvZNpQUIo8Z5F3BvnQJW16OwaHJGCoW0BEoIDrb79gsLzXwg+VYLTxAZRti6pxAPW4QVEhiwXLf6JNGHPDniJ64KnxADhI1ci4PvAQnCOXfWrB1ApdJZ+gLolcDReKyC69CMIi4oUYoWuH3QKtLfVSZRQXbSQ== root@03351470-autossh
[INFO] testing ssh connection
[INFO] listing host keys
usage: ssh-keyscan [-46cHv] [-f file] [-p port] [-T timeout] [-t type]
[INFO] command args: -M 0 -N -q -o ServerAliveInterval=20 -o ServerAliveCountMax=3 autossh@ -p 22 -i /data/ssh_keys/autossh_rsa_key -R 127.0.0.1:8123:172.17.0.1:8123 -v
		   [host | addrlist namelist] ...
OpenSSH_7.5p1-hpn14v4, LibreSSL 2.6.3
debug1: Reading configuration data /etc/ssh/ssh_config
ssh: Could not resolve hostname : Name does not resolve

From the log, copy the public key displayed below [INFO] public key is:

In this example this is:

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDZZ9V6nb+on+nuaAU1MLPPEGm+tv6RP6if3oUQx9bFNBjMuPpytjNUjhX/CZXcIf6IB+K52SYZzNL18ADBTr0oJb4Aog70QU/+LDzX3ljxGTnZBKLBgM+CsOhUgBYw5tpiSTWlBhedKd48xXvhmJ959+2md/x1qNVWXwecNrHUHquWz3CJYcUtY9A4V4PaWz7nFpcGxyWRJaMU+iHexb3Jyf7Cly/EvPxITJ9KE2CbQoRlONF3JYXkgwrjYCa91EXTYOV/S5UR2j9y8FjlYAzmGZqDMQ0G/PzIiYSC7nprl96OdzEVNXHo6NYusRfypDWhkOQi1OEnX0MusVb4Ax34UD/Yt92Kt5zBTFJ+IZJxw5izDbdBSHfngH2orwxFgF+iFAxWmLi6d71B8JdXj/72lTtUmyu4qJBOlN8RMEZOWxmrrnJZutCHZzYqeAYnN6C6rpVpGmUZKyD/FhP1YJB2gcqg87TdH0abjgbRO59g7u7zzFEG4JZeHqzSiDeh6SwWK1VWWn/9iBE3mWvZNpQUIo8Z5F3BvnQJW16OwaHJGCoW0BEoIDrb79gsLzXwg+VYLTxAZRti6pxAPW4QVEhiwXLf6JNGHPDniJ64KnxADhI1ci4PvAQnCOXfWrB1ApdJZ+gLolcDReKyC69CMIi4oUYoWuH3QKtLfVSZRQXbSQ== root@03351470-autossh

5. Stop the add-on.

2. Configure your server

You will need a remote server (which should be accessible from the internet for our purpose).

In this step, we configure our your server to accept the earlier generated public-key for passwordless access.

I strongly recommend creating a new user on your remote server, without any rights or permissions, so in case the access is somehow compromised, this user cant do anything wrong on your server.

  1. $ sudo useradd homeassistant
  2. $ sudo su homeassistant
  3. Check if the file ~/.ssh/authorized_keys exists, create it if not.
  4. Add your earlier generated public key to this file

This step will make sure that your Hass.io add-on can connect through SSH to your server by authenticating via the Key instead of having to provide a password.

3. Configure Nginx

Installing Nginx and configuring your DNS to point to your server is beyond the scope of this blogpost, luckily there are plenty of great tutorials online to get you started.

In the examples below, I will use the example domain: home-assistant-tunnel.example.com make sure to replace it with your domain.

  1. Navigate to /etc/nginx/sites-available
  2. Create a new file touch home-assistant-tunnel.example.com
  3. Enter the configuration below
server {
  listen 80;
  server_name home-assistant-tunnel.example.com;
  return 301 https://home-assistant-tunnel.example.com$request_uri;
}

server {
    # Secure HTTP (HTTPS)
    listen 443 ssl;
    server_name home-assistant-tunnel.example.com;

    # Certificate Information
    ssl_certificate /etc/letsencrypt/live/home-assistant-tunnel.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/home-assistant-tunnel.example.com/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/home-assistant-tunnel.example.com/fullchain.pem;

    include /etc/nginx/snippets/ssl.conf;
    include /etc/nginx/snippets/letsencrypt.conf;

    location / {
        proxy_pass http://localhost:44400;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}

The example above uses an SSL certificate provided by Let's Encrypt. To properly configure your server with Let's Encrypt, you can follow this tutorial

Please note in the above configuration, I used the port 44400 this can be any unused port on your Nginx server, just make sure to use the same port in the next step (your hassio addon configuration)

Make sure to symlink your new file in the folder /etc/nginx/sites-enabled, and restart the nginx service.

4. Configure the Hass.io add-on

  1. Go back to your home assistant, Hass.io -> Dashboard -> HASS Tunnel
  2. In the config paste the following configuration:
{
  "hostname": "home-assistant-tunnel.example.com",
  "ssh_port": 22,
  "username": "homeassistant",
  "remote_forwarding": [
    "44400:localhost:8123"
  ],
  "local_forwarding": [
    ""
  ],
  "other_ssh_options": "-v",
  "monitor_port": "44401"
}

A few notes here:

  • hostname: your domain
  • username: the username of the user you created on your server in step 2
  • "44400:localhost:8123" 44400 must be the same port you used in the Nginx configuration in step 3, 8123 is port on your raspberry pi that is running the homeassistant (default: 8123)
  • monitor_port: This must be the the remote forwarding port +1 (in our case, 44400 + 1 = 44401). This is the port that autossh will use to check if the connection is still active. Every few seconds autossh will send a small message over that port and if the message wouldn't arrive, autossh will restart the SSH tunnel. Making sure the connection stays active.

3. Start your add-on
4. Make sure start-on boot is on if you want to have this addon start on every reboot

In your log, you should see something like this:

...
debug1: Connecting to home-assistant-tunnel.example.com [IP] port 22.
debug1: Connection established.
...
debug1: Authenticating to home-assistant-tunnel.example.com:22 as 'homeassistant'
...
debug1: Authentication succeeded (publickey).
...
debug1: Remote connections from LOCALHOST:44400 forwarded to local address localhost:8123
...

If you now navigate to https://home-assistant-tunnel.example.com you should see your own home assistant instance running. And you can now access your Home Assistant without being connected to your home network.

In case you reboot your Raspberry Pi, the autossh addon will automatically boot, and connect to your remote server.
In case the tunnel connection is disconnected somehow (because of a temporary network drop or whatever) the autossh application will automatically try to restore the connection.