Jump Host and Proxy
In many production environments, internal servers are not directly accessible from the internet. You must route through a bastion host (also called a jump host). SCP supports this natively via -J (ProxyJump) and SSH config.
Architecture
flowchart LR
LOCAL[Your Machine] -->|SSH| BASTION[Bastion Host]
BASTION -->|SSH| TARGET[Internal Server]
LOCAL -.->|SCP data| TARGET
Your SCP data flows through the bastion host transparently — you interact as if connecting directly to the target.
ProxyJump (-J)
The -J flag is the modern, recommended way to route through a jump host.
Example: Single Jump Host
Command:
scp -J user@bastion.example.com ./deploy.tar.gz admin@internal-server:/opt/releases/
Output:
deploy.tar.gz 100% 150MB 32.0MB/s 00:04
Example: Jump Host with Non-Standard Port
Command:
scp -J user@bastion:2222 ./config.yml admin@10.0.0.50:/etc/app/
Output:
config.yml 100% 2048 1.5MB/s 00:00
Example: Chained Jump Hosts
Route through multiple bastion hosts in sequence:
Command:
scp -J user@jump1.example.com,user@jump2.example.com ./data.csv admin@target:/imports/
Output:
data.csv 100% 50MB 20.0MB/s 00:02
SSH Config for Jump Hosts
Define the proxy in ~/.ssh/config so you don't need -J every time:
Host bastion
HostName bastion.example.com
User jump-user
Port 22
IdentityFile ~/.ssh/bastion_key
Host internal-db
HostName 10.0.0.100
User admin
Port 22
IdentityFile ~/.ssh/internal_key
ProxyJump bastion
Example: Using Config Alias
Command:
scp ./backup.sql internal-db:/backups/
Output:
backup.sql 100% 200MB 28.0MB/s 00:07
No -J needed — the config handles it automatically.
Combining with Other Flags
All standard SCP flags work with jump hosts:
Example: Jump + Recursive + Compression
Command:
scp -J user@bastion -rC ./project/ admin@internal:/opt/apps/project/
Output:
index.html 100% 4096 1.5MB/s 00:00
app.js 100% 8192 2.0MB/s 00:00
style.css 100% 2048 1.2MB/s 00:00
package.json 100% 1024 0.8MB/s 00:00
Example: Jump + Port + Identity
Command:
scp -J admin@bastion:2222 -P 8022 -i ~/.ssh/deploy_key ./release.bin deploy@target:/opt/
Output:
release.bin 100% 500MB 25.0MB/s 00:20
Legacy ProxyCommand
For older SSH versions without -J support, use ProxyCommand in ~/.ssh/config:
Host internal-legacy
HostName 10.0.0.100
User admin
ProxyCommand ssh -W %h:%p bastion
Or inline with -o:
Command:
scp -o "ProxyCommand ssh -W %h:%p bastion" ./file.txt admin@10.0.0.100:/tmp/
Output:
file.txt 100% 4096 1.0MB/s 00:00
Common Pitfalls
| Issue | Cause | Fix |
|---|---|---|
Connection timed out | Bastion firewall blocks your IP | Whitelist your IP in bastion security group |
Permission denied on target | Key not authorized on internal host | Copy key to internal server separately |
| Slow transfers | Double encryption overhead | Use faster cipher (-c aes128-gcm@openssh.com) |
-J not recognized | Old OpenSSH version (pre-7.3) | Upgrade or use ProxyCommand |
What's Next?
Encountering errors? Check Common Errors for solutions to frequent SCP problems.