What is tunneling? To put it simply, tunneling is the mechanism by which one port on your local machine redirects to another port on another machine. To understand what it means and why it's useful, let's look at a few use cases.
Imagine you are working on a remote server, example.com
. This server has a pretty standard configuration: Varnish, Apache, ...
Let's now say that for some reason you are having troubles with the web server but you are not sure whether the problem is coming from Varnish or from the application itself. So you need to access Apache, but since Apache is listening on localhost, you can't just go to http://example.com:8000
, you won't be able to connect. Here comes SSH tunneling to the rescue:
ssh -L 8000:127.0.0.1:8000 example.com
What does this do? It creates a tunnel between the local port 8000
on your machine to the IP address 127.0.0.1
and port 8000
on the remote machine. So, when you go to http://127.0.0.1:8000
, your connection enters the tunnel and comes out on the other side knocking on Apache's door:
Browser -> 127.0.0.1:8000 -> SSH --+ # your machine
|
Apache <- 127.0.0.1:8000 <- SSH <-+ # the server
The full syntax of the local forward is this :
ssh -L bind:port:host:hostport example.com
By default, SSH will bind to all your network interfaces. So if you are connected to a network, and have an IP address (192.168.0.10 for example), anyone can connect to port 8000 on your machine and access the remote server:
Developer 2 # other machine
|
+--> 192.168.0.10:8000 -> SSH --+ # your machine
|
Apache <- 127.0.0.1:8000 <- SSH <-+ # the server
Maybe the access to this server is sensitive, and you don't want anybody to come and fiddle with it. In this case, you can specify which network interface you want to bind to, and maybe restrict it to localhost:
ssh -L localhost:8000:127.0.0.1:8000 example.com
Let's go a little further. Imagine now that you want to access a web server located on example2.com
. The problem is,
example2 is inside a private network and you don't have direct access to it. However,
example1 and
example2 are on the same network, and you have access to
example1. This is the typical situation where you have access to a
bridge machine which then gets you access to other machines. This is useful for us because SSH can redirect not only to a local port, but to any port on any machine we have access to on the remote server:
ssh -L 8000:example2.com:80 example1.com
Here is what happens : you enter the tunnel on port 8000 on your machine, get out on machine example1.com
and then ask the operating system: "get me to machine example2.com on port 80".
Browser -> 127.0.0.1:8000 -> SSH --+ # your machine
|
example2.com:80 <- SSH <--+ # example1
You can use aliases for this as well. If you regularly need to forward ports to/from the same host, you can do this in your ~/.ssh/config
Host ex1
User user1
Hostname example1.com
Host ex1proxy
User user1
Hostname example1.com
LocalForward 8000 127.0.0.1:80
Which translates to:
ssh ex1 # ssh [email protected]
ssh ex1proxy # ssh [email protected] -L 8000:127.0.0.1:80
You can of course use multiple forwards at the same time. So the following is valid:
ssh [email protected] \
-L 8000:127.0.0.1:80 \
-L 8080:127.0.0.1:8080 \
-L 8000:example2.com:80
As well as:
Host ex1proxy
User user1
Hostname example1.com
LocalForward 8000 127.0.0.1:80
LocalForward 8080 127.0.0.1:8080
LocalForward 8000 example2.com:80
Finally, if you just want to use SSH to redirect ports, but do not need to launch commands on the remote server, you can do so with -N
:
ssh ex1proxy -N & # launch SSH in daemon mode
[1] 30604 # PID of the process
When you want to kill it:
jobs
[1]+ Running ssh ... # list background jobs
fg 1 # bring job to the foreground
^CKilled by signal 2. # stop it with CTRL+C
Or:
kill 30604
[1]+ Done ssh ...
While I used the same port 8000
for the local and remote machine throughout this post, you don't have to. So the following is just as valid:
ssh -L 9000:127.0.0.1:8000 example.com
Privileged ports still apply. So binding to port 80 for example requires you to sudo:
$ ssh -L 80:127.0.0.1:8000 example.com
Privileged ports can only be forwarded by root.
$ sudo ssh -L 80:127.0.0.1:8000 example.com
Password: ********
# SUCCESS
Tunneling is an invaluable tool in your arsenal, and you should definitely get familiar with it. As usual, you can find more information in the man:
man ssh
man ssh_config
Until next time, Cheers!