In tunneling, or port forwarding, a local port is connected to a port on a remote host or vice versa. So connections to the port on one machine are really connections to a port on the other machine.
The ssh(1) options -f (go to background), -N (do not execute a remote program) and -T (disable pseudo-tty allocation) can be useful for connections that are used only for creation of tunnels.
In regular port forwarding, connections to a local port are forwarded to a port on a remote machine. This is a way of securing an insecure protocol or of making a remote service appear as local. Here we forwarded VNC in two steps. First make the tunnel:
$ ssh -L 5901:localhost:5901 -l fred desktop.example.org
Then on the local machine, connections to the forwarded port will really be connecting to the remote machine.
Multiple tunnels can be specified at the same time. The tunnels can be of any kind, not just regular forwarding. See the next section below for reverse tunnels. For dynamic forwarding see the section Proxies and Jump Hosts.
$ ssh -L 5901:localhost:5901 \ -L 5432:localhost:5432 \ -l fred desktop.example.org
If a connection is only used to create a tunnel, then it can be told not to execute any remote programs (-N), making it a non-interactive session, and to drop to the background (-f).
$ ssh -fN -L 3128:localhost:3128 -l fred server.example.org
Note that -N will work even if the authorized_keys forces a program using the command= option. So a connection using -N will stay open instead of running a program and then exiting.
A reverse tunnel goes the opposite direction of a regular tunnel. In a reverse tunnel, a port on the remote host is forwarded to the local host. Once the connection is made, it works the same as a regular tunnel. Connections to the destination port on the local host connect to the remote host's port.
On the machine that will become the remote machine, open a reverse tunnel.
$ ssh -fNT -R 2022:localhost:22 -l fred server.example.org
Then on the local machine, connecting to the forwarded port as the local host, will open the connection to the machine hosting the reverse tunnel.
$ ssh -p 2022 -l fred localhost
A common use-case for reverse tunneling is when you have to access a machine that is behind a firewall that blocks incoming ssh but without changing the firewall settings, and you have direct access to a second machine outside the firewall. It is easy to make a reverse tunnel from the machine behind the firewall to the second machine. Then to conect to the first machine from outside, connect to the forwarded port on the second machine. The second machine on the outside acts as a relay server to forward connections to the machine on the inside.
Adding or Removing Tunnels within an Established Connection
It is possible to add or remove tunnels, reverse tunnels, and SOCKS proxies to or from an existing connection using an escape sequence. The default escape character is the tilde (~) and the full range of options is described in the manual page for ssh(1). Escape sequences only work if they are the first characters entered on a line and if followed by a return. When adding or removing a tunnel to or from an existing connection, ~C, the command line is used.
To add a tunnel in an active SSH session, use the escape sequence to open a command line in SSH and then enter the parameters for the tunnel:
~C L 2022:localhost:22
To remove a tunnel from an active SSH session is almost the same. Instead of -L, -R, or -D we have -KL, -KR, and -KD plus the port number. Use the escape sequence to open a command line in SSH and then enter the parameters for removing the tunnel.
Adding or Removing Tunnels within a Multiplexed Connection
There is an additional option for forwarding when multiplexing. More than one SSH connection can be multiplexed over a single TCP connection. Control commands can be passed to the master process to add or drop port forwarding to the master process.
First a master connection is made and a socket path assigned.
$ ssh -S '/home/fred/.ssh/%h:%p' -M server.example.org
Then using the socket path, it is possible to add port forwarding.
$ ssh -O forward -L 2022:localhost:22 -S '/home/fred/.ssh/%h:%p' email@example.com
Since OpenSSH 6.0 it is possible to cancel specific port forwarding using a control command.
$ ssh -S "/home/fred/.ssh/%h:%p" -O cancel -L 2022:localhost:22 firstname.lastname@example.org
For more about multiplexing, see the Cookbook section on Multiplexing.