See all OpenBSD related FAQ
How do I use and jump through one server to reach another using ssh on a Linux or Unix-like systems? Is it possible to connect to another host via an intermediary so that the client can act as if the connection were direct using ssh? Can you give me SSH ProxyCommand and ProxyJump example?

You can jump host using ProxyCommand. Some times you can only access a remote server via ssh by first login into an intermediary server (or firewall/jump host). So you first login into to the intermediary server and then ssh to another server. You need to authenticate twice and the chain can be long and is not limited to just two hosts. This page provide SSH ProxyCommand examples for new Linux and Unix developers or sysadmins.
Tutorial details
Difficulty level Easy
Root privileges No
Requirements Linux or Unix terminal
Category Terminal/ssh
Prerequisites ssh command
OS compatibility BSD Linux macOS Unix
Est. reading time 4 minutes

Our SSH ProxyCommand example setup

The SSH set up is as follows to remote hosts though a proxy or bastion with ProxyJump and other options:

     +-------+       +----------+      +-----------+
     | Laptop|       | Jumphost |      | FooServer |
     +-------+       +----------+      +-----------+


               OR

     +-------+       +----------+      +-----------+
     | Laptop|       | Firewall |      | FooServer |
     +-------+       +----------+      +-----------+
    192.168.1.5       121.1.2.3         10.10.29.68

I can can only access a remote server named ‘FooServer’ via ssh by first login into an intermediary server called ‘Jumphost’. First, login to Jumphost:
$ ssh vivek@Jumphost
Next, I must ssh through the intermediary system as follows:
$ ssh vivek@FooServer

Passing through a gateway or two

I can connect to the target host named www.nixcraft.com by first making a ssh connection to the jump host called hello.vpn.cyberciti.biz and then establishing a TCP forwarding to the ultimate destination from there:
$ ssh -J Jumphost FooServer
$ ssh -J Jumphost vivek@FooServer
$ ssh -J hello.vpn.cyberciti.biz www.nixcraft.com
$ ssh -J hello.vpn.cyberciti.biz:22 vivek@www.nixcraft.com

Command to use when the -J option not available

In older versions of openssh the -J is not available. So use the following syntax:
$ ssh -o ProxyCommand="ssh -W %h:%p Jumphost" FooServer
$ ssh -o ProxyCommand="ssh -W %h:%p vivek@hello.vpn.cyberciti.biz" vivek@www.nixcraft.com
$ ssh -o ProxyCommand="ssh -W %h:%p vivek@hello.vpn.cyberciti.biz" root@wp-admin-server

The oldest clients don’t support the -W option

In this case the ssh -tt command. Instead of typing two ssh command, I can type the following all-in-one command. This is useful for connecting to FooServer via firewall called ‘Jumphost’ as the jump host:
$ ssh -tt Jumphost ssh -tt FooServer
$ ssh -tt vivek@Jumphost ssh -tt vivek@FooServer
$ ssh -tt vivek@Jumphost ssh -tt vivek@FooServer command1 arg1 arg2
$ ssh -tt vivek@Jumphost ssh -tt vivek@FooServer htop
$ ssh -tt vivek@Jumphost ssh -tt vivek@FooServer screen -dR

Where,

  • The -t option passed to the ssh command force pseudo-tty allocation. This can be used to execute arbitrary screen-based programs on a remote machine. Multiple -tt options force tty allocation, even if ssh has no local tty.

How to pass through a gateway using stdio forwarding

The syntax is simple as explained above. You no longer need nc installed due ProxyCommand syntax:
$ ssh -o ProxyCommand="ssh -W %h:%p jumphost.nixcraft.com" server1.cyberciti.biz
Say the user accounts names are different on the two Unix or Linux server. Here, ‘tom’ is the account on the second machine which is the final target. The user ‘jerry’ is the account on the intermediary or jump host:

$ ssh -l tom \
      -o 'ProxyCommand ssh -l jerry %h nc server2.nixcraft.com 22' \
      -o 'HostKeyAlias server2.nixcraft.com' \
      server1.cyberciti.biz

An updated version of my ~/.ssh/config file:

Host webserver
        Hostname www42.cyberciti.biz
        ProxyCommand ssh jumphost.nixcraft.com -W %h:%p
 
Host mysftpserver
        HostName sftpserver.cyberciti.biz
        HostKeyAlias sftpserver.cyberciti.biz
        ProxyCommand ssh jumphost.nixcraft.com -W %h:%p

Now all I have to do is type the following ssh command or sftp command:
$ ssh webserver

How to pass through One or more gateways/firewall using ProxyJump

OpenSSH version 7.3 or above includes simple syntax for ~/.ssh/config file:

Host forum
        HostName www.nixcraft.com
        ProxyJump vivek@jumhost.nixcraft.com:22
        User vivek

One can set multiple jump host using a comma-separated list and the servers will be visited in the order listed:

Host www-admin-box
        HostName www.cyberciti.biz
        ProxyJump tom@jumphost1.cyberciti.biz:22,jerry@jumphost2.cyberciti.biz:42
        User vivek

How do I recursively chain gateways using stdio forwarding?

Try the following ProxyJump syntax hich is available starting with OpenSSH version 7.3 or above in your ~/.ssh/config file:

Host nixcraftserver1
        Hostname hello.vpn.cyberciti.biz
        User vivek
        IdentityFile /home/vivek/.ssh/nixcraftserver1_e25519
        Port 22
 
Host nixcraftserver2
        Hostname 192.168.2.25
        User vivek
        IdentityFile /home/vivek/.ssh/nixcraftserver2_e25519
        Port 22
        ProxyCommand ssh -W %h:%p nixcraftserver1
 
Host nixcraftserver3
        Hostname 10.8.0.5
        User fred
        IdentityFile /home/vivek/.ssh/nixcraftserver3_e25519
        Port 22
        ProxyCommand ssh -W %h:%p nixcraftserver2

Next I type the following:
$ ssh nixcraftserver3

Say hello to the ProxyCommand with netcat (older method)

The syntax is as follows and works with all clients
$ ssh -o ProxyCommand='ssh firewall nc remote_server1 22' remote_server1
$ ssh -o ProxyCommand='ssh vivek@Jumphost nc FooServer 22' vivek@FooServer
##########################################
## -t option is needed to run commands ###
##########################################
$ ssh -t -o ProxyCommand='ssh vivek@Jumphost nc FooServer 22' vivek@FooServer htop

The netcat (nc) command is needed to set and establish a TCP pipe between Jumphost (or firewall) and FooServer. Now, my laptop (local system) is connected to Jumphost it now connected FooServer. In this example, the utility netcat (nc) is for reading and writing network connections directly. It can be used to pass connections to a 2nd server such as FooServer.

Update ~/.ssh/config file (older method with netcat [nc])

Edit the $HOME/.ssh/config file using a text editor such as vi, enter:
$ vi ~/.ssh/config
Append the following configuration:

Host fooserver
HostName FooServer
User vivek
ProxyCommand ssh vivek@Jumphost nc %h %p

Save and close the file. Where,

  1. Host fooserver : Set nickname of your choice.
  2. HostName FooServer : Set the real remote server/host name.
  3. User vivek : Set the real user name for remote server/host.
  4. ProxyCommand ssh vivek@Jumphost nc %h %p : Specifies the command to use to connect to the server. In this example, I’m using nc command. Any occurrence of %h will be substituted by the host name to connect, %p by the port, and %r by the remote user name.

To test enter:
$ ssh fooserver
To see the details, pass the -v option to the ssh command. Here is another snippet:

Host server1
HostName v.server1
User root
Port 22
ProxyCommand ssh root@v.backup2 nc %h %p %r

Now, run:
$ ssh -v server1
Sample outputs:

OpenSSH_6.2p2, OSSLShim 0.9.8r 8 Dec 2011
debug1: Reading configuration data /Users/veryv/.ssh/config
debug1: /Users/veryv/.ssh/config line 1: Applying options for server1
debug1: Reading configuration data /etc/ssh_config
debug1: /etc/ssh_config line 20: Applying options for *
debug1: /etc/ssh_config line 102: Applying options for *
debug1: Executing proxy command: exec ssh root@v.backup2 nc v.server1 22 root
debug1: permanently_drop_suid: 501
debug1: identity file /Users/veryv/.ssh/id_rsa type 1
debug1: identity file /Users/veryv/.ssh/id_rsa-cert type -1
debug1: identity file /Users/veryv/.ssh/id_dsa type -1
debug1: identity file /Users/veryv/.ssh/id_dsa-cert type -1
debug1: Enabling compatibility mode for protocol 2.0
debug1: Local version string SSH-2.0-OpenSSH_6.2
debug1: Remote protocol version 2.0, remote software version OpenSSH_6.6.1p1 Ubuntu-2ubuntu2
debug1: match: OpenSSH_6.6.1p1 Ubuntu-2ubuntu2 pat OpenSSH*
debug1: SSH2_MSG_KEXINIT sent
debug1: SSH2_MSG_KEXINIT received
debug1: kex: server->client aes128-ctr hmac-md5-etm@openssh.com none
debug1: kex: client->server aes128-ctr hmac-md5-etm@openssh.com none
debug1: SSH2_MSG_KEX_DH_GEX_REQUEST(1024<1024<8192) sent
debug1: expecting SSH2_MSG_KEX_DH_GEX_GROUP
debug1: SSH2_MSG_KEX_DH_GEX_INIT sent
debug1: expecting SSH2_MSG_KEX_DH_GEX_REPLY
debug1: Server host key: RSA d2:07:84:79:21:a7:84:84:14:ef:f1:7a:84:a5:a1:7s
debug1: Host 'v.server1' is known and matches the RSA host key.
debug1: Found key in /Users/veryv/.ssh/known_hosts:37
debug1: ssh_rsa_verify: signature correct
debug1: SSH2_MSG_NEWKEYS sent
debug1: expecting SSH2_MSG_NEWKEYS
debug1: SSH2_MSG_NEWKEYS received
debug1: Roaming not allowed by server
debug1: SSH2_MSG_SERVICE_REQUEST sent
debug1: SSH2_MSG_SERVICE_ACCEPT received
debug1: Authentications that can continue: publickey,password,keyboard-interactive
debug1: Next authentication method: publickey
debug1: Offering RSA public key: /Users/veryv/.ssh/id_rsa
debug1: Server accepts key: pkalg ssh-rsa blen 279
debug1: Authentication succeeded (publickey).
Authenticated to v.server1 (via proxy).
debug1: channel 0: new [client-session]
debug1: Requesting no-more-sessions@openssh.com
debug1: Entering interactive session.
debug1: Sending environment.
Welcome to Ubuntu 14.04.2 LTS (GNU/Linux 3.13.0-52-generic x86_64)

 * Documentation:  https://help.ubuntu.com/
Last login: Sun May 17 15:41:26 2015 from 10.70.203.66

The sftp syntax

The syntax is as follows:

sftp -o 'ProxyCommand=ssh %h nc firewall.nixcraft.net.in 22' \
       -o 'HostKeyAlias=firewall.nixcraft.net.in' \
       vivek@server1.nixcraft.net.in

Conclusion

You learned about SSH ProxyCommand and ProxyJump command with examples. Here is a quick summary:
SSH ProxyCommand and ProxyJump example
See openssh docs here for more info or read them using the man command or help command:
$ man sshd
$ man sshd_config
$ man ssh_config
$ man ssh
$ man sftp

This entry is 20 of 23 in the Linux/Unix OpenSSH Tutorial series. Keep reading the rest of the series:
  1. Top 20 OpenSSH Server Best Security Practices
  2. How To Set up SSH Keys on a Linux / Unix System
  3. OpenSSH Config File Examples For Linux / Unix Users
  4. Audit SSH server and client config on Linux/Unix
  5. How to install and upgrade OpenSSH server on FreeBSD
  6. Ubuntu Linux install OpenSSH server
  7. Install OpenSSH server on Alpine Linux (including Docker)
  8. Debian Linux Install OpenSSH SSHD Server
  9. Configure OpenSSH To Listen On an IPv6 Address
  10. OpenSSH Server connection drops out after few minutes of inactivity
  11. Display banner/message before OpenSSH authentication
  12. Force OpenSSH (sshd) to listen on selected multiple IP address only
  13. OpenSSH Change a Passphrase With ssh-keygen command
  14. Reuse SSH Connection To Speed Up Remote Login Process Using Multiplexing
  15. Check Syntax Errors before Restarting SSHD Server
  16. Change the ssh port on Linux or Unix server
  17. OpenSSH Deny or Restrict Access To Users and Groups
  18. Linux OpenSSH server deny root user access / log in
  19. Disable ssh password login on Linux to increase security
  20. SSH ProxyCommand example: Going through one host to reach server
  21. OpenSSH Multiplexer To Speed Up OpenSSH Connections
  22. Install / Append SSH Key In A Remote Linux / UNIX Servers Authorized_keys
  23. Use ssh-copy-id with an OpenSSH Server Listening On a Different Port

🥺 Was this helpful? Please add a comment to show your appreciation or feedback.

Vivek Gite is an expert IT Consultant with over 25 years of experience, specializing in Linux and open source solutions. He writes about Linux, macOS, Unix, IT, programming, infosec, and open source. Follow his work via RSS feed or email newsletter.

15 comments… add one
  • Jalal Hajigholamali May 18, 2015 @ 8:41

    Hi,
    Thanks a lot…
    Nice article

  • DrScriptt May 19, 2015 @ 2:40

    Good article Vivek.

    If you liked this and want to see how to take it to the next level, take a look at my Empowering OpenSSH article

    I use this technique to reach hundreds of servers 2 or 3 or 4 jumps deep in my clients network. It works like a champ.

  • Rabin May 19, 2015 @ 16:46

    just a note, you can use -W instead running nc
    ProxyCommand ssh gateway -W %h:%p

    • MJ Mar 18, 2017 @ 11:50

      I don’t have `nc` on the jumpbox, so this worked better. Thanks :)

  • Mike T. May 23, 2015 @ 22:34

    Why are you using fooserver in your example?? Is that server 1, server 2, a server at a Chinese food restaurant?? Just use common sense terms (server 1, server 2, local computer, etc.) so that people can understand what you are trying to say.

    Please stop the Foo pollution!! Dumbest thing Linux people do.

  • Mike Hunt Feb 9, 2016 @ 4:44

    I agree with the use of FOO(server).. At first I wasn’t sure and had to look twice. Caught on finaly (my bad?). SERVER1, SERVER2 etc would allow more folk to understand IMHO (My Humble Opinion:). Thanks for the info however..

  • Master Foo May 30, 2016 @ 15:16

    To all the people complaining about the use of Foo: Please go read up on unix hacker culture. There is a rich history behind the chosen meta-syntactic variables in this example. The way I see if, if you are trying to learn SSH before FOO you need to take a step back and read a few dusty books. Show some respect for those who came before you (and provided all this great free software).

    • Master F̶o̶o̶ Jun 20, 2016 @ 9:30

      I don’t know about what hacker culture you’re talking about. And not sure if I really care about it. I am an exclusive UNIX user/sysop/dev since 1994 and always find foo bar bah behehe annoying and more like today’s pseudo-language of lol, rofl, etc, that only shows lack of imagination and shallowness, the same over-confident mindset that gave birth to RTFM partly from inability to verbalize one’s supposed knowledge, partly, and mostly, from the lack of it.
      I bet you’re a perl guy, just because its gibberish syntax makes you feel special.

      • FooDefender Aug 8, 2017 @ 2:13

        Since only 1994? Get off my lawn!

  • Old Unix Dude May 30, 2016 @ 15:17

    Great article however you should be using ‘ssh -W’ instead of ‘ssh … nc’ for the “hop” command.

  • Dale Dec 9, 2020 @ 17:24

    I Have tried to set this up, but when I connect to the openssh jump server and jump to a cisco device it only returns one line at a time and you can not see the entire output. What do I need to do fix this?

    • 👮🛡️ Vivek Gite (Author and Admin) Vivek Gite Dec 9, 2020 @ 19:49

      Start the ssh session with the -v option and see if you get any warnings or errors:

      ssh -v arg1 arg2 user@host

      Look into DNS in your sshd_config on server and turn it off or configure proper name resolution:

       UseDNS no

      Look into multiplexing

  • Miles Raymond May 1, 2023 @ 16:55

    This is a very nice writeup showing the simple way for modern SSH versions as well as the more convoluted way to do it with older SSH versions! A great resource! Thanks!

  • Sam Galope Sep 20, 2024 @ 14:20

    Absolutely! I’d add that while both ProxyCommand and ProxyJump serve similar purposes, ProxyJump (introduced in OpenSSH 7.3) is generally more user-friendly and easier to configure. With ProxyJump, you can specify the jump host directly in the ssh command without needing to create a more complex command chain like you would with ProxyCommand. This not only makes configurations simpler but also improves readability, especially in complex multi-hop setups. It’s great for anyone managing several remote servers with strict security requirements.

Leave a Reply

Use HTML <pre>...</pre> for code samples. Your comment will appear only after approval by the site admin.