ShellYard

June 2, 2026 · ssh · proxyjump · bastion · jump-host · devops

How to SSH Through Multiple Jump Hosts (ProxyJump)

When your target is two or more bastions deep, here's how to chain through them with ProxyJump, set it up permanently in your SSH config, and forward services through the whole chain.

By ShellYard

Some environments don't put your target one hop away. You can reach a bastion, the bastion can reach an inner bastion, and only that host can reach the machine you actually want: laptop → bastion1 → bastion2 → target. Each hop is reachable only from the one before it. Here's how to chain through them cleanly.

The old way (you'll still see it)

The classic pattern uses ProxyCommand with netcat-style forwarding:

ssh -o ProxyCommand="ssh -W %h:%p user@bastion" user@target

It works, but it's clunky and gets unwieldy with more than one hop. Modern OpenSSH has a better answer.

The modern way: ProxyJump (-J)

For a single jump:

ssh -J user@bastion user@target

For a chain, comma-separate the hops in order:

ssh -J user@bastion1,user@bastion2 user@target

SSH connects to bastion1, then through it to bastion2, then through that to target — each leg its own encrypted hop. A security note worth internalizing: ProxyJump is safer than the old habit of forwarding your SSH agent (-A) through each box, because your agent is never exposed to the intermediate hosts. Reach for ProxyJump, not agent forwarding, when you're traversing machines you don't fully trust.

Make it permanent in your SSH config

Typing the chain every time gets old. Put it in ~/.ssh/config once:

Host target
    HostName target.internal
    User me
    ProxyJump bastion1,bastion2

Host bastion1
    HostName bastion1.example.com
    User me

Host bastion2
    HostName bastion2.internal
    User me
    ProxyJump bastion1

Now ssh target traverses the whole chain automatically. This is the setup most people land on once they're hitting the same deep host regularly.

Forwarding a service through the chain

ProxyJump gets your session to the deep host; layer -L on top to forward a service off it through the entire chain:

ssh -J user@bastion1,user@bastion2 -L 8080:internal-api:8080 user@target
# then hit localhost:8080

That's how you reach a database, API, or desktop that's several hops in — combine the jump chain with a port forward.

The friction

Multi-hop means multi-everything: credentials or keys for each bastion, config entries to maintain, and the same localhost-rewriting and tunnel-lifecycle issues from single-hop forwarding, now stacked. As environments grow, the SSH config sprawls, and every tool that needs the deep host needs its own forward through the chain.

Doing it once, for everything

The way I handle deep environments now is to define the jump path once and let every session use it. In ShellYard, a connection's jump chain is part of its configuration, and the same path serves your shells, API requests, database connections, and remote desktops — so you're not maintaining parallel tunnels through the same bastions for four different tools. It's free, runs locally, and needs no account. Download it here.

The single-hop versions of these tasks are covered in the companion guides: internal APIs, databases, and RDP/VNC behind a bastion, with the fundamentals in SSH port forwarding explained.