SSH Tunneling

Static Port Forwarding

Tunnel Through a Firewall

You can ssh to a server, but you can't connect to any other ports on it. No problem, just tunnel a local port.

localhost --> some.server

ssh -N -L 3389:localhost:389 you@some.server
            |      |      |             |                                     
      Local Port   |      |             |                   
               localhost  |             |
                  Destination Port      |                                                                               
                                                                                         Destination Server    

Now you can connect to localhost:3389 as if you were connecting to some.server:389

Tunnel Through an Intermediary Host

Unlike above, you can't ssh to a server. But you can login to a 'gateway' server, and then ssh from there. No problem, just tunnel a local port though that intermediary.

localhost --> ssh.server.public --> ldap.server.private

ssh -N -L 3389:ldap.server.private:389 you@ssh.server.public
            |          |            |             |                                     
      Local Port       |            |             |                   
             Destination Server     |             |
                            Destination Port      |
                                              Your user ID and intermediate SSH Server  

Now you can connect to localhost:3389 as if you were connecting to some.server:389. This assumes that the intermediary server can connect to the back-end server. (Apply the multiple host technique if not). NOTE: while your tunnel to the first server is encrypted, the second connection is not.

Tunnel Through Two Hosts

(TODO - apply as below but last host is localhost)

Forwarding Through Multiple Hosts

Let's say there's more than one server you need to traverse. The issue is you can only port-forward one hop at a time.

localhost --> ssh.public --> ssh2.private --> ldap.private

The key here is to expose locally, the port of the next SSH server in the chain. You can then use it, as if you were able to talk to it directly.

ssh -f -N -L 2201:ssh2.server.private:22 you@ssh.server.public
               |          |            |             |                                     
         Local Port       |            |             |                   
                Destination Server     |             |
                               Destination Port      |
                                                 Your user ID at the first SSH Server  

localhost:2201 -----(through the public ssh server)------> ssh2.private:22

Now that your local port 2201 forwards to the next SSH server, you can connect as so:

                                              Local port to the intermediary SSH
ssh -f -N -L 3389:ldap.server.private:389 -p 2201 you@localhost
               |          |            |              |                                     
         Local Port       |            |              |                   
                Destination Server     |              |
                               Destination Port       |
                                                Your local user ID   

                localhost:2201 -----(through the public ssh server)------> ssh2.private:22

Now your local port 3389 connects to the remote LDAP server. If instead you had more SSH servers to go though, you could add them as successive ports 2202, 2203, and so forth until you reach your destination.

Dynamic Port Forwarding

Dynamically forward ports, or hop through two servers using Dynamic Port Fowarding (SOCKS, SSH and TSOCKS)


In short:

$ ssh -f -N -D 1080
$ tsocks some_command

So what do you do when you want to forward more than one port ?  You can use the SOCKS proxy feature of your ssh client to forward all traffic. This normally only works for SOCKS aware apps, however you can combine ssh and the tsocks package to transparently proxy normal applications. If you have a java app, you're in luck because the JVM supports SOCKS natively, by specifying a SOCKS jvm parameter.

First, get the tsocks package. You'll want it regardless

$ sudo yum install tsocks

Second, configure tsocks to point at your local host. More detail here

$ sudo vim /etc/tsocks.conf

local =
server =
server_type = 4
server_port = 1080

Also make sure any remote hosts you want to get to can be resolved.  You can do this by pre-pending to your /etc/dhcp/dhclient.conf file, editing your hosts file, etc.  Otherwise, you'll be stuck using IP addresses.

Next, connect your local host to an SSH server with the Dynamic port forwarding feature on. (this should be a server that can see the other side of the network)

$ ssh -D 1080

Now you can connect with:

$ tsocks ssh gattis@internal.server.private

Other commands will work as well. If you have a java application, and the parameter like so:

java -DsocksProxyHost= 

Chain of forwarding.

You can in practice, chain together several hosts to access remote networks, and combine SOCKS and port forwarding. Lets say you want to socks proxy to the gateway server, then portforward from that to another server. 

First, you create the SOCKS proxy

ssh -D 1080

Now, instead of logging onto the server as above, you forward a port though it to a more distant host, that the gateway server itself couldn't reach

$ tsocks ssh -f -N -L 1804:database.very.private:1804 gattis@internal.server.private