Brain Dump

A place to store my random thoughts and anything else I might find useful.

Linux: How to tunnel X over ssh through an intermediate host

Posted by mzanfardino on September 23, 2008

There have been times when I’ve needed to have access to some X application on a remote desktop that I could not access directly. However, I did have access to another machine on the same network via ssh. For instance, at work there is a server that is exposed to the outside world that I can access via ssh. Once connected, I can further ssh to my desktop which is not directly available to the outside. NOTE: Now that we have a properly configured VPN, this processes is not as much in demand.

Here is the general form I use when I want to use ssh tunneling to tunnel X through the intermediate server to the outside world (say from home) to access my work desktop:

General Form:

ssh -f $intermediate_host -L $local_port:$destination_host:$source_port sleep 5; ssh -X localhost -p $destination_port

So, say the public facing host ($intermediate_host) has IP address of (this address could not be public, of course, as 192.168.x.x are non-routeable addresses). Let’s further assume that the internal address of the desktop workstation ($destination_host) is (this address is also a non-routeable address and would not be visible to the outside world). Since we are going to tunnel X over ssh, we are going to want to actually tunnel ssh over a port other than the standard ssh port (22). The local port ($local_port) can be any unused port, so for this example I will choose 9999. The source post ($source_port) will be 22 as this is the port ssh uses. With this information I can rewrite the general form as:

ssh -f -L 9999: sleep 5; ssh -X localhost -p 9999

The first parameter (-f) requests ssh to go to background just before command execution. This is done because we expect ssh to prompt for a password when connecting to the remote machine (see man ssh).

The second parameter (-L) specifies that the given port ($local_port) on the local host is to be forwarded to the given host and port ($destination_server:$source_port) on the remote machine. Therefore ‘-L 9999:’ tells ssh to map local host port 9999 to port 22 on remote host

We have to issue some sort of command when tunneling, so we use ‘sleep 5’. The could be something else, but ‘sleep 5’ will suspend execution of the calling thread for 5 second (see man sleep) which is sufficient to create the tunnel.

The command following the semicolon (;) must be appended to the original command and should not be broken into a separate step. Once the tunnel to the intermediate host ($intermediate_host) is established ‘ssh -X localhost -p 9999’ will be executed. This is the command that forwards X to the host over ssh through the tunnel. The ‘localhost -p 9999’ statement configures ssh to open a localhost connection at port 9999 ($local_port) which is being tunneled to the destination host ($destination_host) which for this example is at port 22.

Pretty simple. When you first issue the command you will be required to provide passwords for both the intermediate host ($intermediate_host) and destination host ($destination_host). NOTE: this example assumes that you are logging into both hosts withe the same user name. If this is not the case, simple append ‘$intermediate_host_username@’ and/or ‘$destination_host_username@’ to each of the servers as appropriate:

General Form:

ssh -f $intermediate_host_username@$intermediate_host -L $local_port:$destination_host_username@$destination_host:$source_port sleep 5; ssh -X localhost -p $destination_port

Example 1:

ssh -f foo@ -L 9999:bar@ sleep 5; ssh -X localhost -p 9999

That’s it! You now have X tunneling through an intermediate host, thereby providing you with a pseudo-vnc connection. Of course, this all assumes that you have X running on your local machine as well. Now, given the general forms above, it shouldn’t be much of a stretch to write a fairly simple (and complete) bash script to automate this task. I’ll leave that exercise for another time.

Example 2:

Recently I had a need to tunnel through an intermediate host to access a remote customer server. The network admin has restricted access for ssh from specific IP addresses. The intermediate host originates from a qualifying address, hence tunneling through this host. To further complicate matters, I needed to port-forward port 902 in order to use vmware-server-console to perform maintenance on a crashed virtual machine. I will not debate the merits of maintaining a server running VMWare Server 1.0.10 with an up-time in excess of 1090 days (as of this writing)!

The following command is used to access the remote server through an intermediate host while port-forwarding port 902:

$ ssh -f intermediate_user@intermediate_host -L 9999:destination_host:22 sleep 5; sudo ssh -L 902:localhost:902 destination_user@localhost -p 9999

Note the use of “sudo” when establishing the port-forwarding. Root authority is required to port-forward any port <1024, so your intermediate user must have the authority to elevate rights to root via sudo. Alternatively you could configure the intermediate server to permit root user access from remote thereby eliminating this requirement, however it’s never a good idea to open ssh to root access!


One Response to “Linux: How to tunnel X over ssh through an intermediate host”

  1. mzanfardino said

    If you have a need, as I have recently, to tunnel http traffic through a remote server over ssh, the syntax is as follows:
    ssh -L unused_post:url:80 ssh_host
    So, for example, I needed to get to from my office, but for reasons I still don’t understand I can not navigate there directly. I have a remote server, let’s call it, that I used to port forward http though. The syntax looked like:
    ssh -L
    I then navigated on my local machine to http://localhost:9999 which redirected my through (logged in as foo) to!

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: