SCP through SSH gateway connection

If you want to access a ssh server behind another ssh server, simply use "ProxyCommand". Example: add to .ssh/config

Host Alice  
   User myLoginAtAlice # optional 
   ProxyCommand ssh -o Compression=no gateway netcat -w 90 %h %p
   ServerAliveInterval 30
   Compression yes

Host gateway
   HostName gateway.public.ip
   User myLoginAtTheGateway # optional 
   Compression yes

Then, you can simply "ssh Alice" or "rsync" or "scp" directly using "Alice" as hostname. The magic is hidden to the client.

This allows you to quickly reconfigure your ssh in case your network topology/configuration changes, and just change the .ssh/config, instead of changing every script.

Explanation: ssh uses the command given as "proxy command" as transport instead of a direct TCP connection. Netcat is a network tool that (among millions of other features) simply redirects its stdin/stdout to the specified remote host. So, "ssh gateway nc sshserver 22" connects you to the ssh server of that machine. %h is the hostname and %p is the port. Such setup allows you to specify "Port N" to change the port without changing the ProxyCommand line.

I activate compression to the final computer and disable outer compression since compressing encrypted or compressed data does not reduce the data volume any further. Any fiddling with the compression settings is also of course optional.


I had exactly the same problem as this but I got it to work without radically changing everything.

All I did was add $SSH_ORIGINAL_COMMAND to the gateway authorized_keys to pass through anything down the the chain to the final server.

So this:

#/home/Alice/.ssh/authorized_keys
command="ssh -t alice@web" ssh-rsa ABCD...E== alice@somehost

Becomes:

#/home/Alice/.ssh/authorized_keys
command="ssh -q -t alice@web $SSH_ORIGINAL_COMMAND" ssh-rsa ABCD...E== alice@somehost

The -q is used to suppress the connection closed message from the end point machine so it does not end up in the local output if using redirection locally.

You can then use scp like this:

scp localFileName [email protected]:/path/on/end/point/remoteFileName

This has has the added advantage of letting users pass command through commands to the end point server and get the result back in their local session so they can redirect them into a file or a pipe them to a different program.

For example:

ssh -t [email protected] "ls -l" > tmp

This works because it seems sshd populates the environment variable $SSH_ORIGINAL_COMMAND with and command specified by the ssh client but I am not sure why this miraculously allows scp to pass through to the endpoint machine as well as commands.