SSH ProxyJump and ProxyCommand: How to Use Jump Hosts

To reach a private host through a jump host in one command, use the -J flag, as in ssh -J jump.example.com target.internal. The flag tells your SSH client to connect to the jump host first and tunnel through it to the target, without leaving a copy of your session on the jump host. A jump host, also called a bastion, is a gateway server that sits between you and machines that have no direct route from the outside.
The guide covers the -J flag, the ProxyJump directive in your SSH config, chaining through several hosts, and the older ProxyCommand approach, all with copy-pasteable examples, then looks at why running fleets of jump hosts becomes a burden at scale and what replaces them with identity-based access.
The one-liner. ssh -J jump.example.com target.internal connects through a single jump host. Add more hosts as a comma-separated list to chain jumps.
What is SSH ProxyJump?
ProxyJump is a built-in OpenSSH feature that routes your connection to a target host through one or more intermediate jump hosts. ProxyJump was added in OpenSSH 7.3 and replaced a pile of awkward ProxyCommand workarounds with a single, readable option. The point of a jump host is reachability, since production databases and internal servers usually live on private networks with no public address, and the bastion is the one machine exposed to let authorized users in.
The fastest way to use it is the -J flag on the command line. The value is the jump host, and the final argument is the target you actually want to reach.
ssh -J [email protected] [email protected]
Your client opens a connection to the jump host, then establishes an encrypted connection through it to the target, so the target sees a connection arriving from the bastion while your session stays end to end between your machine and the target.
How to configure ProxyJump in your SSH config
Typing the -J flag on every connection becomes tedious, so the cleaner approach is to record the jump in your SSH config file at ~/.ssh/config. A host block with a ProxyJump directive lets you reach the target by name, and the client applies the jump automatically.
Host target
HostName target.internal
User alice
ProxyJump jump.example.com
With that saved, ssh target connects through the bastion with no extra flags. You can define the jump host as its own block too, which keeps its address and user in one place and lets several targets reference it by alias. Our article on SSH configuration (ssh_config) covers host blocks, aliases, and defaults in more detail.
Host jump
HostName jump.example.com
User alice
Host target
HostName target.internal
User alice
ProxyJump jump
Multi-hop jumps
Sometimes one bastion is not enough, and you have to pass through a second gateway to reach a deeply isolated host. ProxyJump chains as a comma-separated list, and the client hops through each host in order from left to right.
ssh -J jump1.example.com,jump2.example.com target.internal
The same chain works in the config file by pointing ProxyJump at several hosts, which is easier to maintain than a command line as the path grows. Each hop is authenticated in turn, so every jump host along the way still enforces its own access rules.
Host target
HostName target.internal
ProxyJump jump1.example.com,jump2.example.com
ProxyJump versus ProxyCommand
ProxyCommand is the older mechanism, and it runs an arbitrary command to open the connection to the target rather than using the built-in jump logic. The common form uses SSH’s own -W option to forward the connection through the intermediate host, which is effectively what ProxyJump does under the hood.
Host target
HostName target.internal
ProxyCommand ssh -W %h:%p jump.example.com
Reach for ProxyJump in almost every case, because it is shorter, clearer, and handles multi-hop cleanly. Reach for ProxyCommand when you need something ProxyJump cannot express, such as routing through a tool other than SSH or wrapping the connection in a custom transport. The %h and %p tokens expand to the target host and port, which is how the command knows where to forward.
Conditional jumps with Match exec
Sometimes you want a jump host only in certain conditions, such as when you are outside the office network but not when you are already inside it. The Match directive with an exec test runs a command and applies the block only when that command succeeds, which lets you set ProxyJump dynamically instead of hardcoding it.
Match host target.internal exec "test -z \"$INSIDE_NETWORK\""
ProxyJump jump.example.com
The block applies the jump only when the INSIDE_NETWORK variable is empty, so a connection from inside the network reaches the target directly while a connection from outside routes through the bastion. Match exec runs on your local machine before the connection opens, so the test can check anything the shell can answer, such as the current network name, a reachable host, or a VPN state. Keep these rules readable, because a config full of conditional jumps is powerful but harder for a teammate to follow than a plain host block.
Common ProxyJump problems and fixes
A few issues trip people up with ProxyJump, and most come down to where authentication happens. The frequent one is a permission-denied error at the jump host, which means the client could not authenticate to the bastion itself, so check that your key is loaded and that your username on the jump host is right rather than assuming the target is at fault. Naming the user explicitly on each hop, as in ssh -J alice@jump target, removes the ambiguity.
Agent forwarding is the other common confusion. ProxyJump does not need the -A agent-forwarding flag, because your client authenticates to each host directly rather than hopping from the bastion, so you get the safety of never exposing your agent on the jump host. Avoid adding -A out of habit, since forwarding your agent to a bastion you do not fully control is exactly the exposure ProxyJump was built to prevent.
A non-standard SSH port on a jump host is the last snag. Specify the port on the host that uses it, either inline as jump.example.com:2222 in the -J value or with a Port line in that host’s config block, and keep the target’s own port separate. Getting the port on the right hop is usually what fixes a jump that hangs or refuses the connection.
Beyond jump hosts: identity-based access
Jump hosts solve reachability, but a fleet of bastions becomes its own problem. Each bastion is a public-facing server that has to be patched, monitored, and protected, and it holds SSH keys and access rules that drift out of sync across a team. The bastion is also a standing attack surface, since it is exposed by design, and a stolen key or a missed patch on the jump host can open a path to everything behind it.
Identity-based access removes the jump host as a thing to manage. Instead of exposing bastions and distributing keys, a proxy authenticates each user through the company identity provider, issues a short-lived certificate, and brokers the connection to the target with least-privilege policy and a full audit record, so there is no permanent gateway credential to steal and access expires on its own. Teleport replaces bastion fleets with one identity-aware proxy for servers, databases, and Kubernetes clusters through Teleport Zero Trust Access. For the background concepts, our article Tutorial for Setting Up an SSH Jump Server explains bastions in depth, and the VPN and bastion alternative page covers the replacement approach.
SSH ProxyJump FAQ
What is ProxyJump in SSH?
-J flag, as in ssh -J jump.example.com target.internal, or with the ProxyJump directive in your SSH config. The feature replaced older ProxyCommand workarounds with a single readable option in OpenSSH 7.3.How do I jump through multiple hosts?
ssh -J jump1,jump2 target, and in the config file it is ProxyJump jump1,jump2 inside the target’s host block. Each hop authenticates in turn.What is the difference between ProxyJump and ProxyCommand?
ssh -W %h:%p jump. ProxyJump is clearer and handles multi-hop cleanly, so prefer it unless you need a custom transport that only ProxyCommand can express.Is a jump host the same as a bastion?
How do I set up ProxyJump in my SSH config?
ProxyJump jump.example.com under Host target. After saving it to ~/.ssh/config, running ssh target connects through the bastion automatically with no extra flags.Conclusion
ProxyJump is the modern way to reach a private host through a bastion, whether you use the -J flag for a quick connection or the ProxyJump directive in your SSH config for repeat use, and it chains cleanly through multiple hops. ProxyCommand remains useful for custom transports, but ProxyJump covers almost every case. As bastion fleets grow into a patching and key-management burden, identity-based access replaces the jump host entirely.
Table Of Contents
Teleport Newsletter
Stay up-to-date with the newest Teleport releases by subscribing to our monthly updates.
Tags
Tags
Teleport Newsletter
Stay up-to-date with the newest Teleport releases by subscribing to our monthly updates.
Related Articles

SSH configuration: ssh_config
What is ssh_config? How do you configure an SSH client with it? This blog post offers some of our favorite tips and tricks!

How to Set Up an SSH Jump Server
In this blog post we explain how to set up an SSH jump server using two open source projects.

SSH Tunneling Explained
SSH tunneling transports data streams within an existing SSH session. This post explains different tunneling techniques and features as supported by OpenSSH.