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.