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
- Ensure that
GatewayPorts yes
is present in Linux Server 2's/etc/sshd/sshd_config
file. If it isn't there, add it and restartsshd
. - Use an ssh client and connect to Linux Server 1.
- Execute this command:
ssh -nNT -R 3333:localhost:22 myusername@linuxserver2.com
. Here is an explanation of the parameters:-n
= prevents reading fromstdin
(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 one3333
= the port on the remote side that should be forwarded to this machinelocalhost:22
= our hostname and port number where ssh is runningmyusername@linuxserver2
= our ID/hostname on Linux Server 2
- Use the "port forwarding" feature on
Firewall #2
and forward port 3333 toLinux Server 2
- 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 fromLinux 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 onLinux Server 2
receives the request and forwards it toLinux Server 1
(using the reverse tunnel created in step 2 above) - the
sshd
service running onLinux 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 throughLinux 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 withnohup
(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 toSnn_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