Menu

Creating a persistent ssh tunnel in Ubuntu

In situations when no VPN is either not available or you just think it’s an overkill to configure an ssh tunnel can be a pretty good alternative. An SSH tunnel works by setting up an ssh connetion between two hosts and use that connection to transport normal network traffic. On one side of the tunnel, the OpenSSH software takes anything that is sent to a specific port and sends it over to the other side of the connection. When the packets arrive on the target side, the OpenSSH software forwards them to the correct local port. Natrually the traffic is encrypted on it’s way, thereby creating a miniature VPN.

Setting up an ssh tunnel is quite straigt forward, for example at the terminal:

ssh -NL 8080:127.0.0.1:80 root@192.168.10.10

Let’s break that down:

-N means that SSH should just create the connection and then do nothing.

-L means that the local side is the listening side. If you want it the other way around, use -R instead.

8080:127.0.0.1:80 tells ssh that the listening side should listen on port 8080 of it’s localhost interface and the other side should forward it to port 80. So, on the machine that runs this command, anything sent to 127.0.0.1:8080 is forwarded to port 80 on the other side

root@192.168.10.10 tells ssh to connect to 192.168.10.10 with username root

There’s really only one problem with this. Whenever the ssh connection breaks the tunnel will break and you have to rerun that command again. Depending on your situation this might be a problem and that’s why autossh exists.

Autossh

Autossh is a tool that sets up a tunnel and then checks on it every 10 seconds. If the tunnel stopped working autossh will simply restart it again. So instead of running the command above you could run:

autossh -NL 8080:127.0.0.1:80 root@192.168.10.10

Note: starting an ssh tunnel with autossh assumes that you have set up public key authentication between the client and server since there’s no way for autossh to ask you for the password. Especially if you want to follow the rest of this article and have the tunnels start automatically. Please read more here for details on how to setup public key authentication.

Start automatically

Having autossh monitor your tunnels is a great advantage, but it still requires a command to be run whenever autossh itself would die, such as after a reboot. If you want your ssh tunnels to persist over a reboot you would need to create a startup script. Since Ubuntu 9.10 (Karmic) Ubuntu have used Upstart as its main mechanism to handle startup scripts so the rest of this article will discuss how such a script can be created.

I wanted to achieve three things with my startup script. First, I’d like my tunnel to come up when the computer boots. Second, I’d like to be able to keep configuration for multiple tunnels in one file. And lastly, I’d like to be able to control (start/stop) my tunnels without having to kill individual ssh processes.
Three files are created:

Rationale for each file

/etc/init/autossh.conf
This is the main startup script. The first parts of the file sets the conditions that triggers this script to start or stop. I’ve told my script to start as soon as the local filesystem is ready and when mu network interfaces are up. Chances are that you want to modify this to suit your computer, at least the name of the network interfaces.
The actual script part is a simple bash script that checks the contents of a config file to determine how many tunnels that needs to be started. It then starts a numer of autossh_host jobs with an individual id that happens to correspond a the line number. It would have been nice to just start the autossh processes directly from this script, but autossh is a blocking command and only the first line would be executed on startup. Dropping the process to the background using a & character at the end would work but the resulting autossh processes would be out of our controll.

/etc/init/autossh_host.conf
This is the job where the interesting part actually happens. Note that this script doesn’t have any “start on” stanza at all, it’s only ever started when the main job tells it to start. The interesting part is its “stop on” stanza that simply says that it should stop whenever the parent job is stopped. Using this mechanism all child jobs can be controlled via the parent job.

The script part uses a very naive method of picking out the correct line from /etc/autossh.hosts and use that line as the argument for autossh. Note that with this approach, the config file /etc/autossh.hosts can’t contain any empty lines or comments at all. Room for improvement.

/etc/autossh.hosts
This is just a config file with one row per ssh tunnel to create. Each line consists of the entire parameter line sent to autossh. Again, please note that the parsing of this file is very naive and won’t allow for any blank lines or comments at all.
Starting the tunnels
If everything is correctly set up, you should now be able to start your tunnels using:

sudo start autossh

and stopping them with

sudo stop autossh

If you have problems, check out the logfiles under /var/log/upstart. There should be one logfile for each script/instance, so expect to find autossh.log as well as many autossh_host-N.log.

Questions? Did I miss something? Is my solution entierly wrong? Let me know in the comments.

Post navigation

20 thoughts on “Creating a persistent ssh tunnel in Ubuntu”

When setting this up I got caught out by the fact that the destination host wasn’t in the root user’s known_hosts file. This caused things to fail silently (didn’t produce any output in the error logs), so it took me a while to figure out what was going on. I had tested the autossh command manually – but not as the root user, since I generally avoid running commands as root unless absolutely necessary.

TLDR; Test all connections manually as the *root* user first to ensure known_hosts gets populated.

It doesn’t work for me.
I did exactely what you wrote. I only changed the names of my interfaces (eth0 and wlan0). I rebooted but autossh wans’t running.
I even started it with : sudo start autossh
The tunel wasn’t on.

If the public key authentication between the client and server was created by using another user than root; say myuser, then you need to change the line that says:
exec autossh $ARGS
of the file /etc/init/autossh_host.conf to
exec su myuser -c “autossh $ARGS”

So far I haven’t had to deal with systemd for any of my projects. As far as I know the Upstart scripts are still working even on the newest Ubuntu (might be wrong). If (or when) I get to the point where I have to learn it, I’ll write another post about it and link it from here. But right now, You’re probably already know more than I do.

If i just run the below while logged in as hp-admin it works….this is a default Ubuntu 14 install so root is not used:
autossh -M 5122 -N -R 0.0.0.0:2222:localhost:65534 hp-admin@10.10.2.210 -i /home/hp-admin/.ssh/sshkey

Works well on my new Ubuntu 13.10 install. Ubuntu seems to have moved on to other auto start mechanisms, but I was stuck with 13.10 for hardware reasons and your solution was a perfect fit. Many thanks.