SSH via multiple hosts or bastions
Method 1 – onion (nested tunnels)
With OpenSSH 7.3 and later:
Host webserverA
ProxyJump bastionA,bastionB
The same via command line:
$ ssh -J bastionA,bastionB webserverA
Alternatively (also with 7.3; don't mix this and above):
Host webserverA
ProxyJump bastionB
Host bastionB
ProxyJump bastionA
With older versions – mostly identical (but doesn't automatically copy options like ssh -v
):
Host webserverA
ProxyCommand ssh bastionB -W %h:%p
Host bastionB
ProxyCommand ssh bastionA -W %h:%p
This method initiates all connections locally, setting up a ssh -W
tunnel to each step. Therefore authentication happens locally (ForwardAgent and GSSAPIDelegateCredentials are not required) and your local .ssh/config
applies to each step as well. Server-side, only basic "TCP forwarding" support is needed, same as when using -W
or -L
.
However, each layer adds extra overhead, since it ends up carrying SSH in SSH in SSH in SSH.
Note that each host, except for the outermost one, lists a ProxyCommand through the server immediately before it. If you had 3 servers, you would use [webserverA via bastionC], [bastionC via bastionB], and [bastionB via bastionA].
Method 2 – hop by hop
Host webserverA
ProxyCommand ssh bastionA -A ssh bastionB -W %h:%p
This method initiates connections hop by hop, running ssh
on each hop to connect to the next one. Therefore a ssh-agent and ForwardAgent
must be enabled (or GSSAPIDelegateCredentials
if you use Kerberos); any other special .ssh/config
settings must be copied to all bastion hosts.
On the other hand, it incurs less protocol overhead (max. two layers at every step).
(Edit: added -A
to always request agent forwarding.)