Must I sftp to an intermediate server?

Solution 1:

From your local machine you can create am SSH tunnel through the intermediate host to the final host:

ssh user@intermediate -L 2000:final:22 -N

This will open port 2000 on your localhost that will connect directly to the final server on port 22, by tunneling through the intermediate host. Now in another prompt connect with sftp on port 2000 to be tunneled through to the final server, noting that the user specified here is for the final host:

sftp -P 2000 user@localhost

Seems like this belongs on superuser.com or serverfault.com though.

Solution 2:

Since I originally wrote this answer, OpenSSH has added an easier way to do this. If you have at least OpenSSH 8.0 on your home machine and 7.3 on the intermediate host, you can use the new jump host (-J) option:

sftp -J user@intermediatehost user@finalhost

If you have at least 7.3 on both the home and intermediate hosts, you can do the same thing with the ProxyJump option in your ~/.ssh/config file:

Host finalhost
    ProxyJump user@intermediatehost

With that entry, you can use sftp, scp, and ssh to finalhost, and it'll automatically invoke the tunnel. The only nontransparent part is that it'll prompt for two passwords (intermediatehost followed by finalhost), but if you want you can eliminate that as well with SSH keypairs.

If you don't have new enough versions of OpenSSH, you can still use the ProxyCommand option to do essentially the same thing:

sftp -o "ProxyCommand=ssh -e none user@intermediatehost exec /usr/bin/nc %h %p 2>/dev/null" user@finalhost

(That's assuming the intermediate host has netcat installed as /usr/bin/nc -- if not, you may have to find/install some equivalent way of gatewaying stdin&stdout into a TCP session.)

And the equivalent ~/.ssh/config option:

Host finalhost
    ProxyCommand ssh -e none user@intermediatehost exec nc %h %p 2>/dev/null

See the OpenSSH Cookbook on Wikibooks for more info.

Solution 3:

You can pipe data to the ssh process running on your machine, then run a command on the intermediate machine which reads stdin and sends it to sftp as appropriate.

This can be done in a oneliner on your local machine, though the quoting of arguments to ssh will require care. I am on my phone right now so unfortunately cannot type the details. Perhaps somebody else can complete this answer as an exercise!