For the last 3 years to manage my ‘smart home’ (a couple of lights, heating, some sensors) I have been using Home Assistant running on Dell Wyse Z90D71. And to be honest - it is a great piece of code which works without issues since then. But after the month of using it2 I wanted to have it available through a mobile app - for example, to turn on the heating before I come back. Or make sure that, after leaving for groceries, a bathroom door is open so my cat can use his litter box. ;-)

I looked over the ways to expose Home Assistant online and found some services3, but in the end decided to make something my own. To do it I decided to use the things I already know and have - SSH, nginx and remote server in the cloud.

Despite the fact I wanted to tinker with it by myself I was lazy and searched for tools that would allow me to maintain a stable SSH tunnel. After a short research, I found one that fits perfectly my needs - autossh4.

Using autossh (that runs on top of the SSH) I can be sure that the SSH tunnel will be there. Even if the terminal restarts or it will lose network for a couple of minutes (or days) - autossh will restart the connection.

So I set it up and connected all the required stuff and it has worked without any issues5 since then.

So, no more introduction - below are step-by-step instructions on how to do it by yourself!

Steps outline and assumptions

To access service using SSH tunnel we will need a service and remote server that allow us

Exposing the application is pretty straightforward and can be described in a couple of steps:

  1. install autossh,
  2. create a user on the local server (this is the server you have at home) and create a pair of SSH keys,
  3. create a user on the remote server (this is the server on the public internet, like VPS) and add the previously created key as an authorized one,
  4. test SSH connection,
  5. create a service to run and restart autossh on the local server,
  6. configure reverse proxy on the remote server.

For the post, I assume the Linux distribution is Ubuntu Server (both local and remote server) and you have root rights on it (to configure accounts and reverse proxy).

1. Install autossh

Installing autossh on Ubuntu is straightforward:

$ sudo apt install autossh

2. Terminal: Create user and key pair

Create a new account with username autotunnel on the local server, then log in to this account:

$ sudo useradd -m -s /bin/bash autotunnel
$ sudo su -l autotunnel

Then log in to it on the server and create a new SSH key pair - it needs to be created without a password:

$ ssh-keygen -t ed25519 -C "autotunnel"

With default options public key will be by default saved in ~/.ssh/id_ed25519.pub.

3. Remote: Create a user and add the public key to the authorized ones

Commands as above:

$ sudo useradd -m -s /bin/bash autotunnel
$ sudo su -l autotunnel

After logging in you need to copy the value from terminal ~/.ssh/id_ed25519.pub into remote ~/.ssh/authorized_keys, and set proper permission to that file:

$ echo "ssh-ed25519 AAAAlotofletters autotunnel@tarkin" > ~/.ssh/authorized_keys
$ chmod 600 ~/.ssh/authorized_keys

4. Test connection!

After setting accounts and keys you need to test the connection. You can do that by simply connecting using SSH from the local server to the remote server:

$ ssh autotunnel@remote-tld

If you are trying to log in for the first time - and as this is a fresh account it probably will be the first time - you will need to confirm the authenticity of the remote host:

The authenticity of host 'remote-server.example.com (XX.XX.XX.XX)' can't be established.
ED25519 key fingerprint is SHA256:anotherAlotOfLetters.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])?

Validate the key 6 and if it is correct - continue connecting. After a couple of seconds, you should be logged into the server.

If not - something bad happens or something is misconfigured - for sure it is worth checking if the SSH server allows authenticating with public keys!

5. Create a service to run and manage the connection

To make sure that the connection will start on the local server restart we can create a service that will be enabled and started. To edit file /etc/systemd/system/autotunnel.service ($ sudo nano /etc/systemd/system/autotunnel.service) and type the following content into it:

[Unit]
Description=Keep a tunnel to 'remote-server.example.com' to expose service from localhost:8123
After=network-online.target


[Service]
Type=forking
User=autotunnel
ExecStart=/usr/bin/autossh -f -M 8124 -o ServerAliveInterval=30 -o ServerAliveCountMax=3 -N -R 32100:localhost:8123 autotunnel@remote-server.example.com
ExecStop=/usr/bin/pkill -9 -u autotunnel
Restart=always

[Install]
WantedBy=multi-user.target

The above configuration assumes that we will run the service with user autotunnel. Because you already tested the connection and the key does not require a password there are no additional, manual, steps needed to make a connection.

autossh in the same way as plain ssh will create a tunnel from port 32100 on remote-server.example.com to local 8123 port (it is defined by -R 32100:localhost:8123 part of ExecStart). The only (but crucial!) difference is that it will make sure that the connection will be there. If your local server suddenly becomes unavailable then it will try, continuously, to connect again.

Then reload services, enable and run service type:

$ sudo systemctl daemon-reload
$ sudo systemctl enable autotunnel.service
$ sudo systemctl start autotunnel.service

After a couple of seconds, we should be able to see that the service is running by typing $ sudo systemctl status autotunnel.service.

6. Reverse proxy

To expose the service on the remote server we can use for example Caddy or nginx. For the latter, the full example is available in a post How to expose local service using nginx and SSH. The only required change is the port change - in the linked example we are using 8080 and above we need 32000.

In the case of the Home Assistant, it is required to allow Internet access in System -> Network based on the external domain and port (configured e.g. with nginx as above).

End notes

And that is all - thanks to that solution I can expose any local service (like the mentioned Home Assistant) without requiring static IP, dynamic DNS and so on. I am very happy to have the possibility to turn on the heating before coming home or have an instant notification about water leaks.


  1. A beast with an AMD processor, 4GB of RAM and 120GB SSD! But it cost me less than 200 Złoty (~40 Euro). ↩︎

  2. That is correct - writing this post took me… a few hours typing and three years as an ‘I should write about that’ idea. ↩︎

  3. For Home Assistant there is a service provided by the creators of Home Assistant called Nabu Casa. If you want to offload this to somebody and support the authors - this is the way to go! ↩︎

  4. Description, download and other stuff available here. It should be also available in the repository of any Linux distro. ↩︎

  5. Well, the remote server (VPS) is hosted by OVH and was turned off during the fire in a data centre (SBG), but that is a force majeure↩︎

  6. For example using the command ssh-keygen -lf <(ssh-keyscan localhost 2>/dev/null) on the remote server and verifying the checksum (source: StackExchange↩︎