The ProxyCommand
directive in SSH is a powerful feature that enables connection chaining through intermediate hosts. When examining the configuration:
Host final
Hostname final.com
Port 22
AgentForwarding yes
User guestuser
ProxyCommand "ssh user@bastion.com -W %h:%p"
Here's what actually happens during execution:
- The local SSH client parses the
final
host configuration - It executes the ProxyCommand before attempting direct connection
- The
-W %h:%p
flag tells the intermediate SSH session to:
%h → final.com (target host from Hostname)
%p → 22 (target port from Port directive)
While functionally similar to nc %h %p
, the -W
flag offers several advantages:
- No dependency on netcat being installed on bastion
- Uses SSH's native socket forwarding
- Better handling of TCP connection states
For more complex environments with multiple bastions:
Host final
Hostname final.internal
User appuser
ProxyCommand ssh -q -W %h:%p bastion2
Host bastion2
Hostname jump2.example.com
User gateway
ProxyCommand ssh -q -W %h:%p bastion1
Host bastion1
Hostname gateway.example.com
User admin
The tunnel remains open until:
- Either SSH session terminates
- TCP connection times out
- Explicit disconnect command sent
For latency-sensitive operations:
ProxyCommand ssh -o ControlMaster=auto \
-o ControlPath=~/.ssh/cm-%r@%h:%p \
-o ControlPersist=10m \
bastion -W %h:%p
When working with multi-tier network architectures, SSH's ProxyCommand
becomes an essential tool for traversing bastion hosts. The feature essentially creates a pipe between your local machine and the target host through intermediate jump servers.
Let's analyze the exact sequence when executing ssh final
with your configuration:
1. Local SSH client initiates connection to 'final' host
2. SSH detects ProxyCommand and executes: ssh user@bastion.com -W final.com:22
3. The -W flag establishes a direct TCP forwarding channel:
- Creates SSH connection to bastion.com
- On bastion.com, opens TCP connection to final.com:22
- Bridges STDIN/STDOUT between connections
4. Your local SSH client then communicates through this tunnel
The -W host:port
option is indeed similar to netcat but more robust because:
- It uses SSH's native socket forwarding
- Maintains encryption throughout the entire path
- Automatically handles connection termination
Here's an advanced multi-hop scenario:
Host bastion1
Hostname jump1.example.com
User admin
Host bastion2
Hostname internal-jump.example.com
User deploy
ProxyCommand ssh -W %h:%p bastion1
Host production-db
Hostname db01.internal
User postgres
ProxyCommand ssh -W %h:%p bastion2
While convenient, chained ProxyCommands can introduce latency. For better performance:
# Use ControlMaster for persistent connections
Host *
ControlMaster auto
ControlPath ~/.ssh/control-%r@%h:%p
ControlPersist 1h
The technique is sometimes called "SSH chaining" or "SSH hopping". Other implementations include:
# Using nc (less secure)
ProxyCommand ssh bastion nc %h %p
# Using SSH -J (newer versions)
ssh -J bastion1,bastion2 final