There are two ways to create an SSH tunnel, local and remote portforwarding (there’s also dynamic forwarding, but we won’t cover thathere). The best way to understand these is by an example, let’s startwith local port forwarding.

Imagine you’re on a private network which doesn’t allow connections to aspecific server. Let’s say you’re at work and imgur.com is beingblocked. To get around this we can create a tunnel through a serverwhich isn’t on our network and thus can access Imgur.

$ ssh -L 9000:imgur.com:80 user@example.com

The key here is -L which says we’re doing local port forwarding. Thenit says we’re forwarding our local port 9000 to imgur.com:80,which is the default port for HTTP. Now open your browser and go tohttp://localhost:9000.

The awesome thing about SSH tunnels is that they are encrypted. Nobodyis going to see what sites you’re visiting, they’ll only see an SSHconnection to your server.

Connecting to a database behind a firewall

Another good example is if you need to access a port on your serverwhich can only be accessed from localhost and not remotely.

An example here is when you need to connect to a database console, whichonly allows local connection for security reasons. Let’s say you’rerunning PostgreSQL on your server, which by default listens on the port5432.

$ ssh -L 9000:localhost:5432 user@example.com

The part that changed here is the localhost:5432, which says toforward connections from your local port 9000 to localhost:5432 onyour server. Now we can simply connect to our database.

$ psql -h localhost -p 9000

Now let’s stop here for a little bit an explain what is actually goingon. In the first example the 9000:imgur.com:80 is actually sayingforward my local port 9000 to imgur.com at port 80. You can imagineSSH on your server actually making a connection (a tunnel) between thosetwo ports, one on your local machine, and one on the target destination.

If we however say something like 9000:localhost:5432, it meanslocalhost from the server’s perspective, not localhost on yourmachine. This means forward my local port 9000 to port 5432 onthe server, because when you’re on the server, localhost means theserver itself.

This might be a bit confusing, but it is important to understand whatthe syntax actually means here.

Remote port forwarding

Now comes the second part of this tutorial, which is remote portforwarding. This is again best to explain with an example.

Say that you’re developing a Rails application on your local machine,and you’d like to show it to a friend. Unfortunately your ISP didn’tprovide you with a public IP address, so it’s not possible to connectto your machine directly via the internet.

Sometimes this can be solved by configuring NAT (Network AddressTranslation) on your router, but this doesn’t always work, and itrequires you to change the configuration on your router, which isn’talways desirable. This solution also doesn’t work when you don’t haveadmin access on your network.

To fix this problem you need to have another computer, which is publiclyaccessible and have SSH access to it. It can be any server on theinternet, as long as you can connect to it. We’ll tell SSH to make atunnel that opens up a new port on the server, and connects it to alocal port on your machine.

$ ssh -R 3000:localhost:9000 user@example.com

The syntax here is very similar to local port forwarding, with asingle change of -L for -R. But as with local port forwarding, thesyntax remains the same.

First you need to specify a local port on your machine which you wishto expose publicly, which in this case is 3000. Next there is theaddress on which the server should listen to, and a port on which theserver should listen to, which in this case is 9000.

There is one more thing you need to do to enable this. SSH doesn’t bydefault allow remote hosts to forwarded ports. To enable this open/etc/ssh/sshd_config and add the following line somewhere in thatconfig file.

GatewayPorts yes

Make sure you add it only once!

$ sudo vim /etc/ssh/sshd_config

And restart SSH

$ sudo service ssh restart

After this you should be able to connect to the server remotely, evenfrom your local machine. The way this would work is that you wouldfirst create an SSH tunnel that forwards traffic from the server onport 9000 to your local machine on port 3000. This means that ifyou connect to the server on port 9000 from your local machine,you’ll actually make a request to your machine through the SSH tunnel.

A few closing tips

You might have noticed that every time we create a tunnel you also SSHinto the server and get a shell. This isn’t usually necessary, as you’rejust trying to create a tunnel. To avoid this we can run SSH with the-nNT flags, such as the following, which will cause SSH to notallocate a tty and only do the port forwarding.

$ ssh -nNT -L 9000:imgur.com:80 user@example.com

SSH has a huge number of features, so I’d recommend you to checkout themanual page at man ssh, which contains even more tips.

There’s also an amazing talk called The Black Magic of SSH / SSH Can DoThat?, which I really recommend you towatch.