SSH Tunneling (Port Forwarding)

This is a short introduction to SSH tunnelling (also known as “port forwarding”). we have tried to describe it with some simple examples.

Let’s define our sample setup: We have a PC at home called linuxhome. We want to connect to a computer in london called linuxwork, but we are only allowed to connect to a gateway machine called linuxgate:       

The usual way would be a two step process: first connect from linuxhome to linuxgate and then from linuxgate to linuxwork. Let’s see how a tunnel can help:

* From a Unix-like machine

The following refers to OpenSSH 2.x and 3.x:

On linuxhome we execute this command:

ssh  -l userid  -L 7777:linuxwork:22  linuxgate  cat -

This means: open an ssh connection as user userid to host linuxgate and execute the command cat –. While the session is open, redirect all connections to port 7777 on the local machine to port 22 on machine linuxwork.

Now we can use any SSH command (ssh, slogin, scp, sftp) to connect directly to linuxwork through the tunnel. For example:

ssh -p 7777 localhost uname -a
slogin -p 7777 localhost
scp -p -P 7777 localhost:data/file1.txt .
sftp -o Port=7777 localhost

How it works:

The ssh process on the local machine linuxhome establishes an SSH connection with the sshd server process on the gateway machine linuxgate. It uses the well-known port 22 on the server side and some free port on the local machine, e.g. 605. In addition, because we have used the -L option, the local ssh process accepts local connections to port 7777 and sends all data received on this port through the other port 605 to linuxgate with some marking “this is from tunnel 7777”. The gateway linuxgate has been informed through the -L option that, whenever it receives data marked with “this is from tunnel 7777”, it has to open a connection to host linuxwork on port 22 and send it that data: 


More Details:


  1. The cat – command in the first ssh command is there only to keep the connection open. Any other command which does not finish could be used. It could be left blank, too, thereby opening a shell, but then you need a controlling terminal and cannot use the ssh command in a script. 
  2. You can use any port above 1024 and below 32768 for the -L option. 
  3. If you need to connect to several machines, then just specify more -L options in the first ssh command, one per machine, each with a different local port. For example:
    ssh -l userid -L 7777:linuxwork1:22 -L 7778:linuxwork2:22 
    -L 7779:linuxwork3:22 linuxgate cat -

    then use ssh -p 7777 localhost to connect to linuxwork1, ssh -p 7778 localhost to connect to linuxwork2, etc. 

  4. You can also redirect to other remote ports. For example, if machine linuxwork accepted telnet connections (port 23), then you could prepare the tunnel with:
    ssh -l userid -L 7777:linuxwork:23 gate cat -
    and then just telnet to linuxwork with this command:
    telnet localhost 7777

    The port numbers of usual network services can be found in file ‘/etc/services’.

  5. You can write a small script to setup the SSH tunnel for all connections you normally need and call that script automatically every time you connect from home to the Internet.
  6. You can define aliases for connections which you need very often. For example, if you do (in a tcsh):
    alias ssh linuxwork 'ssh -p 7777 localhost'

    then you can simply do things like:

    ssh linuxwork uname -a

    ssh linuxwork ps -ef

    sshwork (to login)
  7. With some more complex aliases or shell scripts you can almost work as with a direct connection. For example, if you do:
    alias ssh \
    'set target=`echo \!^ | sed -e "s/work/-p 7777 localhost/g"` ; \
    /usr/local/bin/ssh $target \!:2*'

    then you can do:

    ssh work ps -ef 
  8. If you use the -v option for the ssh command which prepares the tunnel, then you can see in its output whenever a connection is established through the tunnel (and other debug messages).


Share this post

Post Comment