Skip to content

SSH Tunneling

Here is how to setup an ssh tunnel. My specific example has the following configuration:

  • Linux Server 1 = the machine I want to connect to from outside a firewall. It runs the sshd daemon, but the firewall has no open ports.
  • Linux Server 2 = a linux machine (running sshd) that I can access from the internet. It is behind a different, but that firewall allows access to SSH.

Below is a text diagram of the configuration:

Steps

  1. Ensure that GatewayPorts yes is present in Linux Server 2's /etc/sshd/sshd_config file. If it isn't there, add it and restart sshd.
  2. Use an ssh client and connect to Linux Server 1.
  3. Execute this command: ssh -nNT -R 3333:localhost:22 myusername@linuxserver2.com. Here is an explanation of the parameters:
    • -n = prevents reading from stdin (necessary when running ssh in the background)
    • -N = don't execute a remote command--just open a tunnel
    • -T = no TTY
    • -R = create a Reverse tunnel instead of a normal one
    • 3333 = the port on the remote side that should be forwarded to this machine
    • localhost:22 = our hostname and port number where ssh is running
    • myusername@linuxserver2 = our ID/hostname on Linux Server 2
  4. Use the "port forwarding" feature on Firewall #2 and forward port 3333 to Linux Server 2
  5. Open an SSH session (ssh, sftp, scp, ...) from outside of either firewall and direct it to the IP/port of Firewall #2. If all goes well, you should receive a login prompt from Linux Server 1. In my case, my command line on Linux Server 2 looked like this:
me@myserver.com:/etc/ssh$ ssh root@localhost -p 3333
Enter passphrase for key '/home/me/.ssh/id_dsa': 
root@myotherserver's password: 
[root@server1 ~]# ls -lrt

Obviously I've changed the names of the servers in the example, but you get the point. From Linux Server 2, I made an ssh connection to localhost and specified the port number that I gave when I made the reverse tunnel from Server 1. I was asked for the passphrase for my DSA key (locally, on Server 2), and then for my password on Server 1.

That's it! The communication flows like this:

  • I use an ssh client to access Firewall #2 on port 3333.
  • The firewall forwards the communication to Linux Server 2
  • the sshd service running on Linux Server 2 receives the request and forwards it to Linux Server 1 (using the reverse tunnel created in step 2 above)
  • the sshd service running on Linux Server 1 responds to the login request according to the way it is configured. In my case, it provides a login prompt.
  • the communication flows from Linux Server 1 back through Linux Server 2 and to the ssh client

and everything proceeds normally after that.

Miscellaneous

Here are a few add-ons that might make this situation easier to deal with:

  • The reverse tunnel will be broken when the ssh client connection that created it is closed. To make it keep running even after the client session disconnects, use the nohup command as shown here. It will continue to run until the connection is broken, the process dies, or the server is restarted.
nohup ssh -nNT -R 3333:localhost:22 myusername@myserver.com;
  • To reestablish the reverse tunnel automatically when it breaks, we need a script. Save this script as reverseTunnel.sh in your home directory and run it with nohup (i.e. nohup reverseTunnel.ssh). This will cause it to run until the server is restarted.
while true; do 
  ssh -nNT -R 3333:localhost:22 myusername@myserver.com; 
  sleep 5; 
done
  • To reestablish the tunnel automatically after a system restart, put a copy of the script above into the /etc/rc3.d directory. This will cause it to run when the system goes into network mode. You might need to rename it to Snn_sshTunnel.sh where "nn" is a 2-digit number that is higher than the number assigned to the ssh daemon's script in the same directory.
  • If the reverse tunnel were made to a machine that is directly exposed to the internet, step 4 above could be ommitted