ssh all the time


Using autossh and reverse ssh tunneling to bust out of NAT'd networks and firewalls automatically.

In another lifetime I blogged about how to reverse an ssh connection. This was by far my most popular post ever. It earned enough in google ad money to cover my hosting costs. Those were the days. Those days are gone, and now lots of people have blogged about using reverse ssh tunnels. It's time to take it to the next level and make reverse ssh tunnels easy and ubiquitous.

I want all of my machines to be setup with an ssh tunnel whenever one of them finds an internet connection. That way I can always access all of my machines no matter where I, or they are the world. I want this even if they are in some high security firewalled corporate prison or if they are sharing the same IP address as the other million NAT'd users tethering internet through their phones. This should happen automatically and without fuss.

To do this you need to have ssh access to a machine that can be seen from the internet, and the ssh daemon machine needs to have the GatewayPorts option set to yes (this is not the default). See my old post for more information.

Here's the recipe.

(Update! I have made this much easier by scripting the whole process, see the bottom of the post!)

Create a file:

/etc/network/if-up.d/reverse_ssh_tunnel

(you are using Ubuntu, right?)

Put this in it:

#!/bin/sh
# ------------------------------
# autossh reverse tunnel on boot
# ------------------------------
# See autossh and google for reverse ssh tunnels to see how this works

# When this script runs it will allow you to ssh into this machine even if it is behind a firewall or has a NAT'd IP address.
# From any ssh capable machine you just type ssh -p $PORT_MIDDLEMAN_WILL_LISTEN_ON localusername@middleman

# This is the username on your local server who has public key authentication setup at the middleman
USER_TO_SSH_IN_AS=change_me

# This is the username and hostname/IP address for the middleman (internet accessible server)
MIDDLEMAN_SERVER_AND_USERNAME=luser@example.com

# The following two numbers can be whatever you want, but need to be unique if you have multiple reverse ssh tunnels
# Port that the middleman will listen on (use this value as the -p argument when sshing)
PORT_MIDDLEMAN_WILL_LISTEN_ON=11829

# Connection monitoring port, don't need to know this one
AUTOSSH_PORT=27554

# Ensures that autossh keeps trying to connect
AUTOSSH_GATETIME=0

export AUTOSSH_PORT AUTOSSH_GATETIME

su -c "autossh -f -N -R *:${PORT_MIDDLEMAN_WILL_LISTEN_ON}:localhost:22 ${MIDDLEMAN_SERVER_AND_USERNAME} -oLogLevel=error -oUserKnownHostsFile=/dev/null -oStrictHostKeyChecking=no" $USER_TO_SSH_IN_AS


Make sure that you fill in the values to match your own logins (send me a comment if you are confused about what to put in).

Now whenever the machine acquires an internet connection it will run the above script (that is why we put it in /etc/network/if-up.d). Then from any internet connection you can ssh -p 11829 USER_TO_SSH_IN_AS@MIDDLEMAN and you will get forwarded to your own machine.

You should put this on all of your machines. That is all.

Oh one more thing. For this to work you need to have passwordless public key authentication working between your machine and the middleman. Use this:


ssh-copy-id


It will take care of all of the gory details of copying and concatenating your keys so that you can ssh in without typing anything.

This blog post is a mess and needs some serious revision, but I needed to post it, if for no other reason so that I could find the info when I needed it!

Update

I put everything you need to set this up into a script on github. If you have a server out on the internet with the GatewayPorts option turned on, then all you need to do is the following:


wget http://github.com/mikeymckay/reverse_ssh_tunnel/raw/master/setup_reverse_tunnel.sh
chmod +x ./setup_reverse_tunnel.sh
sudo ./setup_reverse_tunnel.sh
:

11 Response to ssh all the time

  1. How does one choose which computer to log into through the middle man?

  2. @Johnneylee - when autossh connects to the middle man it chooses an arbitrary port to listen on:

    PORT_MIDDLEMAN_WILL_LISTEN_ON=11829

    Now when you ssh to the middleman on that port, the middleman will redirect you to whichever computer setup that port.

    It is this port that determines which computer will be logged into via the middleman.

  3. @mickeymckay
    Good post, thanks for helping me out with that.

  4. Hi,
    thanks for sharing your script. I adapted it a bit because I dont run SSH on Port 22 in my hostmachine.

    You can find a diff in my Wiki:
    http://wiki.host-consultants.de/doku.php?id=linux:reversessh#diff

  5. hi, first, great script. secondly, a netstat on the middleman did show that the middleman was listening on port 11829. However, after i shutdown my local computer (the computer this script runs on), netstat reveals that the middleman is still listening on port 11829 (of course I can't connect to it anymore cuz the tunnel is destroyed). Why? And then when i turn back on the local computer, then the middleman suddenly stops listening on 11829. Thanks for ur insight and wisdom :)

  6. @Sharad all I can figure is that the middleman is waiting for your local computer to come back online. This is a total guess, but perhaps when the machine recovers and doesn't respond appropriately to the ssh connection then the middleman knows to close the connection. At any rate... glad it helped!

  7. thanks for the prompt reply... i just thought that when the local computer powers down, it rips apart the tunnel and the middleman should stop listening on the 11829 port right away. is there anything we can put in the script that kills the listening socket on the middleman?

  8. M says:

    Hi,

    The command works well, but since the machine I use to ssh into is shared, I would like ssh to use a passphase. Of course I don't know because autossh forks at startup, which means it cannot read a passphase from the stdin.

    Is there some method to get it to read the passphase from a file for example, or initially from stdin and then cache is somewhere for when it has to re-establish the tunnel?

  9. Anonymous says:

    Thanks so much for this wonderful script and especially for the automated setup.

    The way your script allows one to ssh into the remote PC, is there a way one can access web based apps like Webmin or Nagios that are installed on the remote PC (the one behind the NAT/Firewall) using this (or similar) method?

    Thanks once again.

    Warmest Regards.

  10. @bizres - you can use a SOCKS Proxy to access web apps. Look up examples of using ssh to create a Proxy - the tunneled connection works the same as any other ssh connection.

  11. Unknown says:

    I have no idea if you'll reply to this as its been a year (to date) since the last comment, but I used your automated script and have an issue that I hope you can help me resolve. When I do "ssh -p 1337 mylogin@172.0.0.238" (I'm obviously not pasting my correct ssh info) from my home system the connection eventually times out. My current set up actually has both the destination system and the original system at the same public IP. The two systems are different hardware/IPs on the internal network though.

Post a Comment