128

SSH tunneling is very confusing to me. I am wondering if I can do this in Linux.

I have 3 machines..

A. My local machine at home.
B. Machine at work that I can SSH into (middle man).
C. My desktop at work that I can only SSH into from machine B.

So I can SSH from A -> B and from B -> C, but not from A -> C.

Is there a way to setup an SSH tunnel from A through B, so when I run other SSH commands it they just work from my local machine A? I am basically trying to clone a git repo from work to home (and I cannot install git on machine B).

Also, once setup.. How would I unset it as well?

4

8 Answers 8

143

Place this in your .ssh/config file on hostA (see man 5 ssh_config for details):

# .ssh/config on hostA:
Host hostC
    ProxyCommand ssh hostB -W %h:%p

Now the following command will automatically tunnel through hostB

hostA:~$ ssh hostC

You may like to add options like -oCiphers=arcfour and -oClearAllForwardings=yes to speed things up, since wrapping ssh inside ssh is computationally more expensive and the extra effort and the wrapper doesn't need to be as secure when it's tunneling already-encrypted traffic.


If you are using OpenSSH earlier than 5.3, the -W option is not available. In this case you can implement the above using netcat (nc):

ProxyCommand ssh hostB nc %h %p  # or netcat or whatever you have on hostB
6
  • 1
    This is brilliant! Thank you. This solves a problem that has been eating me for the past 2 days: hostC sits behind a firewall and has data I want to access from hostA, a laptop that can be anywhere in the world. hostB is also behind the same firewall with hostC, but it has an SSH port open to the world. Thus I can ssh from hostC -> hostB. I setup a reverse SSH tunnel between hostC & hostB, so I can also ssh from hostB -> hostC (forwarded through localhost). With your trick I can go from hostA -> hostC! It works seamlessly with SCP & Fugu on OSX! Thank you!
    – AndyL
    Mar 7, 2010 at 4:45
  • The -W option should be used instead of the nc option.
    – vy32
    May 3, 2015 at 23:21
  • Which SSH should support -W, only the one on hostA (the origin) or also the one on hostB (the middle machine)?
    – gioele
    May 5, 2015 at 18:09
  • For info, if you have multiple hosts you need to reach via the same hostB, it's possible to declare multiple Host hostC lines above the ProxyCommand making it super easy to access several hosts via the middle server.
    – fduff
    May 19, 2017 at 8:29
  • If you end up here as a Windows user, the ssh command just needs a little fine tuning to work: ProxyCommand ssh.exe hostB -W %h:%p, i.e., ssh.exe instead of ssh.
    – ToJo
    Dec 22, 2021 at 22:50
10

For interactive shell you can use this simple command:

ssh -J <user>@<hostB> <user>@<hostC>

The -J options is for jump.

3
  • This should be the accepted answer! Much simpler than the rest. Only available since OpenSSH 7.3 but that's a few years now.
    – Caesar
    Feb 23, 2021 at 15:49
  • If the hostB uses port≠22, you can use the syntax like user@hostB:port (this wouldn't work for hostC, where you have to use the usual -p option).
    – Ruslan
    Dec 29, 2022 at 7:20
  • the port syntax is OK, but it's almost always better to learn the .ssh/config format. this allows you to create aliases, control all sorts of parameters like port, default user, automatic application of proxyjump, etc.
    – markhahn
    Dec 14, 2023 at 20:04
8

Edit: This is the wrong approach. See ephemient's answer instead. This answer will work, but is potentially less secure and definitely less awesome.

It sounds like you want a solution like the following:

ssh -L localhost:22:machinec:22 machineb

This will get you a shell on machineb. Leave this alone; minimize the terminal window.

Now, whenever you make an ssh connection to localhost, you will actually be connected to machinec through machineb. When you're done with the tunnel, just close the terminal in which you ran the above command.

Note that you'll need superuser privileges to run the command.

2
  • +1 Thanks Wesley. This is the real ssh tunneling answer. Here's an article about it: securityfocus.com/infocus/1816
    – Larry K
    Feb 11, 2010 at 4:18
  • 3
    On the whole, this is quite evil... but I've had to do this with ancient versions of OpenSSH, or other ssh clients. You could pick some high port like 8022: this way it doesn't interfere with any ssh service on localhost, and doesn't require running as root. Just add -p 8022 to your ssh commands. And it's braindead easy with git: use the URI ssh://localhost:8022/path/to/repo.git.
    – ephemient
    Feb 11, 2010 at 4:43
5

Alternatively, since OpenSSH 7.3 introduces a ProxyJump directive:

Host final
  ProxyJump intermediate

In example:

Host intermediate
  Hostname 10.0.0.42
  User root
Host final
  Hostname final.destination.com
  User foo
  ProxyJump intermediate

Then ssh final will jump through the intermediate machine.

3

Sounds like you want a shell alias on A that causes ssh to occur on C

  1. I assume that on A, you can type ssh me@b "ssh me@c hostname" and get back "C"
  2. Make an alias sshc which expands sshc foo into ssh me@b "ssh me@c foo"
  3. For exact syntax of creating the alias, consult superuser.com
2
  • 1
    You may have to add -t to the outer ssh's options if you want an interactive shell, since ssh assumes -T if it's given a command.
    – ephemient
    Feb 11, 2010 at 4:12
  • Note that this is a different category from the better answer (ProxyJump) because you are forming a new ssh connection on the intermediate box, rather than just a tunnel through which the local machine connects to the final host. So you have to trust the intermedia, but don't with ProxyJump. OTOH, this may be necessary/desired if the final box only accepts connections from the intermediate.
    – markhahn
    Dec 14, 2023 at 20:13
0

If your employer provides a VPN, I'd recommend using that instead.

That way, you won't have to configure any applications specially (even ssh), and you can see any machine behind the firewall. Additionally, all of your traffic will be encrypted by the VPN software, which will add security to any inadvertently or deliberately unencrypted traffic.

1
  • 7
    Sometimes its the VPN that is the reason we need these tricks...
    – lsl
    Dec 6, 2012 at 4:18
0

YASS Yet Another Simple Solution

ssh -f -L 2222:HostC_IP_or_Name:22 userOnB@hostB sleep 10 &&
    ssh -o HostKeyAlias=HostC -p 2222 userOnC@localhost
  • First command open a ssh connection to HostB and tell HostB to forward connections from localhost:2222 to HostC:22.
  • the -f parameter tell SSH to go to background once connection established
  • Second command open simply a client connection to localhost:2222
  • Option HostKeyAlias are not required, but could help to prevent connection to wrong host
  • Nota: command sleep 10 are needed to maintain connection until second ssh command use forwarded port. Then first ssh will close when second ssh leave forwarded port.

you could now run subsequent ssh sessions:

ssh -o HostKeyAlias=HostC -p 2222 userOnC@localhost

Variant:

ssh -f -L 2222:HostC_IP_or_Name:22 userOnB@hostB sleep 10 &&
    ssh -M -S ~/.ssh/ssh_HostC22userOnC.sock -o HostKeyAlias=HostC -p 2222 userOnC@localhost

subsequent ssh sessions could be open by running:

ssh -S ~/.ssh/ssh_HostC22userOnC.sock userOnC@localhost

The main advantage of using -M and -S param is that only one connection is open from HostA to HostC, subsequent session won't authenticate again and run a lot quicker.

1
  • ControlMaster is a major win, but basically orthogonal to the question. ControlMaster and Proxyjump is the best.
    – markhahn
    Dec 14, 2023 at 20:15
0

Special case, mixed nix platforms:

  hostA (linux) -> HostB (solaris) -> HostC (linux)

If need an X application on hostC, and the intermediate hop is on Solaris box... in this case I found the netcat (nc) needed on the ProxyCommand like so:

hostA:~$ vi .ssh/config:

Host hostC
    ProxyCommand ssh hostB nc %h %p       # where nc is netcat

Then automatic tunneling works:

hostA:~$ ssh hostC

1
  • happily obsoleted by ProxyJump
    – markhahn
    Dec 14, 2023 at 20:14

You must log in to answer this question.