In some of my older articles, at least where an SSH tunnel is involved, I keep mentioning a specific way of initializing such an encrypted tunnel, which results in the automatic closure of the tunnel after the job on the remote server is finished. Since this is my method of choice, I decided to provide some detailed explanation in this post, so that it can be used as a reference in future articles.
What is a tunnel
Assume that an SSH and a VNC server are up and running on the machine
remote.example.org. The remote firewall does not allow direct connections to the VNC port – assume that this is TCP port 5901 – from the network, which is generally a good idea. In this case, we will connect to the remote VNC service from the local workstation through the remote SSH server, by using a feature of the SSH protocol, called local port forwarding or, simply, tunneling.
Such a tunnel can be initialized from the local workstation with the following:
[me@local]$ ssh -L 25901:127.0.0.1:5901 email@example.com
When executed, the above statement has the following results:
- forwards the local port 25901 on the local workstation to port 5901 on the remote machine through the ssh connection. The port 25901 is an example and it could be any other available TCP port on the local machine. The result is that any request made on the local port 25901 is transfered to port 5901 on the remote machine through the encrypted SSH connection.
- connects us to the remote SSH server and logs our remote user “
In order to connect to the remote VNC service through that tunnel, it is required to keep the connection to the ssh server open and, from another local terminal, connect to the local port 25901 with the vnc client:
[me@local]$ vncviewer 127.0.0.1:25901:1
By closing the vnc client and by logging out of the remote shell, the tunnel is destroyed too.
A better way
The previous method is too far from being convenient in the everyday use. Things could be a lot better if we could just create the SSH tunnel and launch vncviewer in one line of code. This can be achieved by using the -f and -N flags when connecting to the remote SSH server:
[me@local]$ ssh -f -N -L 25901:127.0.0.1:5901 firstname.lastname@example.org; \ vncviewer 127.0.0.1:25901:1
The -f switch instructs the ssh client to fork the ssh session to the background. Therefore, we remain at our local terminal’s prompt, from where we can execute more commands on our local machine. In this case, with a single line of code, we created the tunnel and executed vncviewer. However, the -f switch has one requirement. It cannot be used on its own. It needs to be accompanied either by the -N switch or we have to execute a specific command on the remote machine.
In this case, the -f -N combination keeps the tunnel up and running in the background, but the drawback is that it runs forever, requiring us to explicitly kill the ssh process if the tunnel is not needed any more. Even if we close vncviewer, the following command confirms that the tunnel is still running, which was actually expected:
[me@local]$ ps ax | grep ssh | grep -v grep
The best way – Tunnels that auto-close
As it has been mentioned previously, instead of using the -f -N switch combination, we can just use -f alone, but also execute a command on the remote machine. But, which command should be executed, since we only need to initialize a tunnel?
This is when
sleep can be the most useful command of all! In this particular situation, sleep has two advantages:
- it does nothing, so no resources are consumed
- the user can specify for how long it will be executed
How these help in auto-closing the ssh tunnel is explained below.
We start the ssh session in the background, while executing the sleep command for 10 seconds on the remote machine. The number of seconds is not crucial. At the same time, we execute vncviewer exactly as before:
[me@local]$ ssh -f -L 25901:127.0.0.1:5901 email@example.com sleep 10; \ vncviewer 127.0.0.1:25901:1
In this case, the ssh client is instructed to fork the ssh session to the background (
-f), create the tunnel (
-L 25901:127.0.0.1:5901) and execute the sleep command on the remote server for 10 seconds (
The difference between this method and the previous one (-N switch), basically, is that in this case the ssh client’s primary goal is not to create the tunnel, but rather to execute the sleep command for 10 seconds. The creation of the tunnel is some kind of side-effect, a secondary goal. If
vncviewer was not used, the ssh client would exit after the 10 sec period, as it would have no more jobs to do, destroying the tunnel at the same time.
During the execution of the sleep command, if another process,
vncviewer in this case, starts using that tunnel and keeps it occupied beyond the 10 sec period, then, even if the ssh client finishes its remote job (execution of sleep), it cannot exit because another process occupies the tunnel. In other words, the ssh client cannot destroy the tunnel because it would have to kill vncviewer as well. When vncviewer stops using the tunnel, then the ssh client exits too, as it has already accomplished its goal.
This way, no ssh processes are left running in the background.
Although this is not a general article about the SSH protocol, the following ssh client switches may prove useful in some situations.
The -C switch may be used in order to apply compression to the transfered data between the local workstation and the remote server. This will save some bandwidth, but will increase the cpu load.
Also, a specific encryption algorithm may be specified with the -c option. The blowfish cipher is a rather good choice, which offers good encryption and low cpu utilization.
[me@local]$ ssh -C -c blowfish -f -L 25901:127.0.0.1:5901 firstname.lastname@example.org sleep 10; \ vncviewer 127.0.0.1:25901:1
Finally, the -v flag can also be used for verbose output.
The Auto-closing SSH tunnels by George Notaras, unless otherwise expressly stated, is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License.