Skip to content

Instantly share code, notes, and snippets.

@talflon
Last active February 22, 2017 18:25
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save talflon/b66eb1542772ee365c3f to your computer and use it in GitHub Desktop.
Save talflon/b66eb1542772ee365c3f to your computer and use it in GitHub Desktop.
Tunneling SSH back through another SSH

If you run a command like this from host1:

$ ssh -N user@host2 -R 12201:localhost:22 \
      -o ServerAliveInterval=10 -o ServerAliveCountMax=2

you can then, from host2, run:

$ ssh -p 12201 user@localhost

to connect back to host1.

The options ServerAliveInterval and ServerAliveCountMax are for noticing if the connection has gone down, and can be set to whatever makes sense. By putting this in a loop, then it can automatically reconnect if the connection is lost. (Just remember to sleep in the loop in case there's no internet or DNS. Also, I've seen it fail to bind the 12201 port if it tries to reconnect too quickly.)

More information in man ssh and man ssh_config.


I wrote a script I named reverse-ssh:

#!/bin/sh

REMOTE_HOST="$1"
FW_PORT="$2"
[ -n "$REMOTE_SSH_PORT" ] || REMOTE_SSH_PORT=22
[ -n "$LOCAL_SSH_PORT" ] || LOCAL_SSH_PORT=22
[ -n "$SSH_LOGIN" ] || SSH_LOGIN=revsshserver

while :
do
    ssh -nNTC -o ServerAliveInterval=60 \
        -R $FW_PORT:localhost:$LOCAL_SSH_PORT \
        -p $REMOTE_SSH_PORT $REMOTE_HOST -l $SSH_LOGIN
    sleep 10
done

and put it on host1. (As I understand it, autossh does more or less the same thing, in probably a better way. I didn't know about that program when I set everything up.) I added the *_SSH_PORT options because I had been using nonstandard SSH ports. I then created the following accounts:

  • revsshclient@host1
    • with a key pair in ~/.ssh/
  • revsshserver@host2
    • with login shell disabled (set to /bin/false in /etc/passwd)
    • with revsshclient@host1's public key in ~/.ssh/authorized_keys

and on host1, ran the reverse-ssh script on startup as the user revsshclient. In my case this was done quickly by adding to /etc/rc.local something like

su - revsshclient -c "REMOTE_SSH_PORT=54321 setsid reverse-ssh host2 12345"

Now, from host2 you can connect to host1 with

ssh -p 12345 myusername@localhost

I usually run a command like this to connect from my work computer:

ssh -p 54321 host2 -t -- ssh -p 12345 myusername@localhost

which will do both connections, from my computer to host2, and from host2 to host1. I have my work computer's SSH key on host2's ~/.ssh/authorized_keys, so that I don't have to type a password for that first connection.

By forwarding port 5900:

ssh -p 54321 host2 -L 5900:localhost:5900 -t -- \
    ssh -L 5900:localhost:5900 -p 12345 myusername@localhost

I can run x11vnc to get graphical access with a command like:

sudo x11vnc -nopw -localhost -display :0 \
    -auth /var/lib/mdm/:0.Xauth
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment