I love explaining this kind of thing through visualization. :-)
Think of your SSH connections as tubes. Big tubes. Normally, you'll reach through these tubes to run a shell on a remote computer. The shell runs in a virtual terminal (tty). But you know this part already.
Think of your tunnel as a tube within a tube. You still have the big SSH connection, but the -L or -R option lets you set up a smaller tube inside it.
Every tube has a beginning and an end. The big tube, your SSH connection, started with your SSH client and ends up at the SSH server you connected to. All the smaller tubes have the same endpoints, except that the role of "start" or "end" is determined by whether you used -L
or -R
(respectively) to create them.
(You haven't said, but I'm going to assume that the "remote" machine you've mentioned, the one behind the firewall, can access the Internet using Network Address Translation (NAT). This is kind of important, so please correct this assumption if it is false.)
When you create a tunnel, you specify an address and port on which it will answer, and an address and port to which it will be delivered. The -L
option tells the tunnel to answer on the local side of the tunnel (the host running your client). The -R
option tells the tunnel to answer on the remote side (the SSH server).
So... To be able to SSH from the Internet into a machine behind a firewall, you need the machine in question to open an SSH connection to the outside world and include a -R
tunnel whose "entry" point is the "remote" side of his connection.
Of the two models shown above, you want the one on the right.
From the firewalled host:
ssh -f -N -T -R22222:localhost:22 yourpublichost.example.com
This tells your client to establish a tunnel with a -R
emote entry point. Anything that attaches to port 22222 on the far end of the tunnel will actually reach "localhost port 22", where "localhost" is from the perspective of the exit point of the tunnel (i.e. your ssh client).
The other options are:
-f
tells ssh to background itself after it authenticates, so you don't have to sit around running something on the remote server for the tunnel to remain alive.
-N
says that you want an SSH connection, but you don't actually want to run any remote commands. If all you're creating is a tunnel, then including this option saves resources.
-T
disables pseudo-tty allocation, which is appropriate because you're not trying to create an interactive shell.
There will be a password challenge unless you have set up DSA or RSA keys for a passwordless login.
Note that it is STRONGLY recommended that you use a throw-away account (not your own login) that you set up for just this tunnel/customer/server.
Now, from your shell on yourpublichost, establish a connection to the firewalled host through the tunnel:
ssh -p 22222 username@localhost
You'll get a host key challenge, as you've probably never hit this host before. Then you'll get a password challenge for the username
account (unless you've set up keys for passwordless login).
If you're going to be accessing this host on a regular basis, you can also simplify access by adding a few lines to your ~/.ssh/config
file:
host remotehostname
User remoteusername
Hostname localhost
Port 22222
Adjust remotehostname
and remoteusername
to suit. The remoteusername
field must match your username on the remote server, but remotehostname
can be any hostname that suits you, it doesn't have to match anything resolvable.
See also:
The feature is called ControlMaster
which does multiplexing over one existing channel. It causes ssh to do all of the key exchanges and logging in only once; thus, the later commands will go through much faster. You activate it using these three lines in your .ssh/config
:
Host host.com
ControlMaster auto
ControlPath ~/.ssh/master-%C
# for openssh < 6.7 you need to use this one:
# ControlPath ~/.ssh/master-%r@%h-%p
ControlPersist 5m
You can adjust it to your needs; one alternative is that you could open one master connection that stays open during your other commands; then you would not need ControlPersist
.
There are many possibilities with this feature to tweak, but make sure you store your ControlPath
socket in a safe place, not readable by other users, otherwise it could be misused.
More info can be found in the ssh_config(5)
manual page.
Best Answer
Second case is very useful in situation when example.com can connect to [google.com] host while your box can't. For example, you have VPN connection which is restricted to a number of boxes, while you want to access host not in list. ssh -L 123:target.host.com:456 user@vpn.host.com.
So, basic usage is to jump INSIDE the network or jump OUTSIDE the network (ssh to some kind of proxy/gateway).
And finally, there may be firewall restrictions on target server which accepts connections only from given hosts.