Skip to main content.

Chaining SSH connections


Live demo in BSD Now Episode 042. | Originally written by Lars, with edits by TJ, for | Last updated: 2014/06/18


With people running BSD as firewalls and routers, many have sshd running on them. That means that they can be used as a gateway to machines behind them. If it's a one-off occurrence, then the connection information only needs to be specified on the command line. If it is done more frequently, it can be set in the user's or system's ssh_config. Doing so needs only a port open for SSH and no further per-destination modification of the firewall rules.

Passing through a gateway using netcat mode

As of OpenSSH 5.4, a "netcat mode" can connect stdio on the client to a single port forwarded on the server. This can also be used to connect using ssh, but it needs the ProxyCommand option either as a run time parameter or as part of ~/.ssh/config. However, it no longer needs netcat to be installed on the intermediary machine(s). Here is an example of using it in a run time parameter.


In that example, authentication will happen twice - first on the jump host, and then on the final host where it will bring up a shell. The syntax is the same if the gateway is identified in the configuration file. ssh expands the full name of the gateway and the destination from the configuration file. The following allows the destination host to be reached by entering ssh server in the terminal:

Host server
  ProxyCommand ssh -W %h:%p

The same can be done for SFTP. Here the destination SFTP server can be reached by entering sftp jump and the configuration file takes care of the rest. If there is a mix up with the final host key, then it is necessary to add in HostKeyAlias to explicitly name which key will be used to identify the destination system.

Host sftpserver
  ProxyCommand ssh -W %h:%p

It is possible to add the key for the gateway to the ssh-agent which you have running, or else specify it in the configuration file. The option "User" refers to the user name on the destination. If the user is the same on both the destination and the originating machine, then it does not need to be used. If the user name is different on the gateway, then the -l option can be used in the ProxyCommand option. Here, the user fred on the local machine logs into the gateway as fred2 and into the destination server as fred3.

Host server
  User fred3

If both the gateway and destination are using keys, then the option "IdentityFile" is used to point to the destination's private key.

Host jump
  IdentityFile /home/fred/.ssh/rsa_key_2

It's also possible to do that more than one layer deep.

Recursively chaining gateways


Host * / *

Do not put a space between the "* / *" - that's only there because of a technical problem with Markdown not displaying it correctly otherwise. In this way, hosts are separated with a slash (/) and can be arbitrary in number.

$ ssh host1/host2/host3/host4

If keys are to be used, then agent forwarding can be specified in the command given in the "ProxyCommand" option using -A and first loading the keys into the agent. The following configuration uses sed to allow different port numbers and user names using the plus sign (+) as the delimiter for hosts, a colon (:) for ports and an equal sign (=) for user names. The basic structure is "ssh $() -W $():$()" and where "%h" is substituted for the target host name.

Host *+*


$ ssh host1+host2:2022+host3:2224

As is, the colons confound sftp, so the above configuration will only work with it using standard ports. If sftp is needed on non-standard ports then another delimiter, such as an underscore (_), can be configured. Any user name except the final one can be specified for a given host using the designated delimiter, in the above it is an equal sign (=). The destination host's user name is specified with -l and all others can be joined to their corresponding host name with the delimiter.


If user names are specified, depending on the delimiter, ssh can be unable to match the final host to an IP number and the key fingerprint in known_hosts. In such cases, it will ask for verification each time the connection is established, but this should not be a problem if the equal sign (=) is used.

Latest News

New announcement



Two Year Anniversary



New discussion segment



How did you get into BSD?



Episode 243: Understanding The Scheduler



Episode 242: Linux Takes The Fastpath



Episode 241: Bowling in the LimeLight



Episode 240: TCP Blackbox Recording

