New White Paper: From Zero Trust to Agent Trust
Read now
Home
Blog
SSH ProxyJump and ProxyCommand: How to Use Jump Hosts

SSH ProxyJump and ProxyCommand: How to Use Jump Hosts

Zephyr Iglesias

Published March 1, 2022
Updated August 13, 2026

SSH ProxyJump and ProxyCommand blog header image

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

ProxyJump is a built-in OpenSSH feature that connects you to a target host through one or more intermediate jump hosts. You use it with the -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.
Give ProxyJump a comma-separated list of hosts, and the client hops through them in order. On the command line that is 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.
ProxyJump is the newer, simpler option that uses SSH’s built-in jump logic, while ProxyCommand runs an arbitrary command to open the connection, often 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.
Yes, the terms are used interchangeably. Both describe a gateway server that sits between you and machines on a private network with no direct external route. You connect to the bastion first, then reach the isolated target through it.
Add a host block for the target with a ProxyJump directive naming the jump host, for example 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.

Tags

Teleport Newsletter

Stay up-to-date with the newest Teleport releases by subscribing to our monthly updates.


Related Articles