SSH Tunneling across multiple hosts in Linux

Sometimes you need to communicate with a server (or other device) that is not directly accessible from your own computer. If you can reach this server via another server this is not an issue and can be solved by setting up a SSH Tunnel across your network.

An example

Let’s start with a example:

  • Computer A is where you are working.
  • Server A is accessible by computer A.
  • Server B has a administration web interface but its IP Address is completely shielded by a firewall; except for Server A.

Thus the only way to reach the web interface on Server B from Computer A would be through Server A.

The solution

You can solve this by setting up an SSH Tunnel which spans several server; the command for this is:

ssh -t -t -L[LOCAL_PORT]:localhost:[PORT_ON_A] [USER]@[SERVER_A] 'ssh -L[PORT_ON_A]:localhost:[PORT_ON_B] [USER]@[SERVER_B]'

Basically you are chaining a specific IP port to guide traffic from and to your PC.

The variables shown here represent:

  • LOCAL_PORT, the port on you local PC where you want to connect to in order to communicate with SERVER_B
  • PORT_ON_A, the port on SERVER_A which is used to transfer your data across to SERVER_B (may be any port number but make sure it does not collide with other tunnels / uses)
  • USER, your account name / login name on SERVER_A and/or SERVER_B
  • SERVER_A, the hostname or IP address of your first jump point
  • PORT_ON_B, the destination port to which you want to connect; in our example we wanted to connect to a web interface (port 80) thus we use the value 80 here
  • SERVER_B, the hostname or IP address of your intended destination

You might notice the use of a double -t argument in our command; this is not an error but is actually required in order to create the connection (without it your system might complain that it is unable to acquire a TTY; explaining the details of this would go beyond this blog posting)

Our example command

To complete this exercise I will show you the full command with which we could satisfy the requirement in our opening example:

ssh -t -t -L8081:localhost:10000 mvriel@a.server.example.com 'ssh -L10000:localhost:80 mvriel@b.server.example.com'

See that we used port 8081 as local port? We did that to prevent collisions with services on our local machine. Were you to use (for example) port 80 it might produce unwanted results such as your local apache (if you have one) being unreachable.

Now all we need to do to visit the website on Server B would be to enter the following URL in your browser:

http://localhost:8081

That’s all there is to it. If anything is not clear, just leave a comment.