Reverse Tunnels

[Since Canonical is abandoning upstart in favor of systemd (2016), my newer configurations will use systemd.]

This page describes how I set up a reverse tunnel so that I can access my private GNU/linux(ubuntu) computer from anywhere on the Internet. I document it here to be helpful to me, but you might also find it helpful.

I must use a publicly accessible, [possibly rented] ubuntu server to access my computer, which is on a private LAN, buried deep within a labyrinth of other, hostile networks that I have no control over. This private computer does not have a public IP address, but can access the public server.

I call the public server, hbelabs.com, and my private computer, mercury. If I use yet another computer, moon, with any modern OS, anywhere on the Internet, I should be able to access mercury, as long as both mercury and moon can ssh to hbelabs.com.

[Note, one may possibly use the public IP address of the server (instead of a name), and the server can indeed be an ordinary PC on a residential service in your home, but some ISPs are making it more difficult to do that by not providing public IP addresses. They instead force you to use (as a "convenience") their own modem/routers when the wire enters your home. This way, they can control your "consumption" of Internet information (including also TV and phone service) and in the process make it more difficult (but not impossible) to offer services and information to the web. This difficulty is compounded by their more recent and deliberate efforts to make sure the public dyanamic IP address (if you can use it) actually changes - in the past, even though it was a "dynamic" IP address, it would not change for months at a time.]

The strategy begins by creating a user called "autossh" on both computers, and give it passwordless access from the private computer to the public server. Of course, I do have a normal user account with ssh access to the public server, but I don't want to use that to establish the reverse tunnel.

Then, the strategy continues by running the program "autossh" using systemd. (I should have picked a different username.)


Create User autossh

On both the public server and the private computer,

The first command creates the user and the second and third commands show how to log in and out as that user. Note that user autossh does not actually have a password.

The "-m" says, create the home directory structure, "/home/autossh/", and the "-u 499" gives him a user ID that might not show up on the usual ubuntu login screen, but also doesn't interfere with the usual numbering of ordinary user IDs, which start near 1000. The "-s /usr/sbin/nologin" disables logins.


Passwordless ssh Access

On the private computer, login to the autossh account and enter the command

The defaults might be OK. Do not enter a password. You must also never share the file "/home/autossh/.ssh/id_rsa" with anyone.

The public key file can be shared. In fact, you want to put it on the public server. But, since we can't use the command "ssh-copy-id", since we have disabled logins, we must use some other way.

This is what I do. cat the file and copy it to your clipboard buffer (use the mouse to select the text, right-click, choose "copy").

That entire second row (which will wrap on your terminal), is what gets copied. Of course, you will use your own public key.

Next, ssh into your public server and log in to the autossh account. As autossh, edit the file "/home/autossh/.ssh/authorized_keys" and paste that public key into it. That key occupies only one line in the file, but will wrap making it look like several lines.

Log off the public server and try to ssh into the autossh account on the public server. It will ask you to confirm the host for known_hosts. Accept. Try logging in using the FQDN and the IP address ... just to be sure those entries are in the known_hosts file. Doing that will display some stuff about the server (indicating it did login), but it will bump you right back to your private computer. That is OK.


Create the reverse tunnel

When you are able to log into the server from the client autossh account without any prompts, we are ready to create the simple script file and put it in a place that ubuntu runs when it is booting up.

My goal is to be able to sit at some computer on the internet and type

$ ssh -p20202 bob@hbelabs.com

to access my private client computer, mercury, even if mercury is sitting at the lightdm login prompt halfway around the world.

First, make sure we can set up the reverse tunnel by hand. While at mercury, enter this

$ sudo su -s /bin/sh autossh -c "/usr/bin/autossh -N -R :20202:localhost:22 autossh@hbelabs.com"

... on one line.

One thing I use to check to see it worked is to log into the server (as bob) and check using

$ netstat -an |grep listen|grep 20202

or variations thereof. If nothing displays, then there is no reverse tunnel.

In order to actually make it work, I have to open up the port 20202 on the public server, so, while still logged into the server, I simply use (Uncomplicated FireWall),

$ sudo ufw allow 20202
$ sudo ufw status
$ sudo ufw enable

the third command of which makes sure it is actually enabled.

Once I figure out and solve all the reasons it might not be working, it is time to set it up to start automatically before the lightdm login prompt, but after we have some network configuration.

Create the file "/etc/network/if-up.d/reversetunnel",

Make sure it is executable and owned by root with

$ sudo chmod a+x reversetunnel
$ sudo chown root:root reversetunnel
$ ls -al reversetunnel
-rwxr-xr-x 1 root root 212 June 27 16:26 reversetunnel

Sometimes (maybe if you have several network cards installed and configured) this does not execute at the right time nor does it actually execute, which can be frustrating. Rather than fight with configuring $IFACE conditionals in the script or the NetworkManager configuration challenges, if you configure the interface with "/etc/network/interfaces", you might be able to put the script in "/etc/networking/" (so ubuntu won't get too confused and you have a chance of finding the script later) and you can add a tab-prefixed line calling the script (as shown in this "interfaces" fragment):

In the script ("reversetunnel"), you can also see the second command that sets up a reverse tunnel to the vnc server. For the VNC tunnel, neither port 15926 (on the server hbelabs.com) nor 5900 (on the client mercury) need be opened up for public access. The VNC will go through ssh port 22 (on the server), which must be open.

I reboot the client mercury, and the server, a few times just to be sure it works automatically.

Now, if I managed to set up x11vnc properly, I can sit at that computer somewhere out on the internet and also type,

$ ssvncviewer -via hbelabs.com localhost:15926

and view the wonderful lightdm login prompt ... and login to its gui and try to break some things.

NOTE: The sole purpose of autossh (the user account) is to use passwordless login from mercury to the public server so it can establish the reverse tunnel. I use my ordinary account to actually use ssh or vnc. autossh, the program tries to keep the ssh connections alive.