Transfer Files Safely with OpenSSH sftp
Get remote and local paths backwards in sftp and you overwrite the wrong file instead of downloading one. This guide keeps the two straight: connect to an SSH server, poke around the remote directory, upload, download and resume a transfer with confidence. The examples use OpenSSH sftp from Ubuntu's openssh-client package, version 1:9.6p1-3ubuntu13.19 on the machine used for this guide.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about fifteen minutes. You need the client package, a remote account with SSH and SFTP access, and a local file or directory you are allowed to move around. You do not need root for normal transfers; remote ownership, permissions and server configuration are separate matters that this guide does not touch.
1. Check the installed client
Confirm the command resolves to the binary you expect and note the package version. Both are ordinary, read-only checks:
$ command -v sftp
/usr/bin/sftp
$ dpkg-query -W -f='${Package} ${Version}\n' openssh-client
openssh-client 1:9.6p1-3ubuntu13.19
The client runs over an encrypted SSH transport and can reuse the same keys and SSH configuration as ssh. SFTP is not FTP with a password prompt bolted on, and it gives you no anonymous access by itself.
Checkpoint
If command -v sftp prints nothing, stop here and install the client through your normal system package process. Do not copy a binary in from an untrusted location.
2. Connect and inspect the remote side
Start an interactive session with a real account and host name, replacing both placeholders below, including the account if it differs from your local user:
$ sftp [email protected]
Connected to HOST.example.
sftp> pwd
Remote working directory: /home/USER
sftp> ls -la
sftp> lpwd
Local working directory: /home/USER
sftp> bye
A host key prompt may appear on the first connection. Read the fingerprint and verify it through a trusted channel before accepting it. A password prompt is expected when password authentication is enabled; it is not proof you have reached the server you intended.
This is the one habit worth building early: pwd reports the remote working directory, lpwd reports the local one. Commands such as ls, get and put take remote and local paths in different positions, and mixing them up is the classic sftp mistake.
3. Download one remote file
Connect again, list the remote path, then use get. Giving an explicit second path makes the local destination unambiguous:
$ mkdir -p "$HOME/sftp-downloads"
$ sftp [email protected]
sftp> cd /remote/path
sftp> ls -l report.csv
sftp> get report.csv /home/LOCAL_USER/sftp-downloads/report.csv
Fetching /remote/path/report.csv to /home/LOCAL_USER/sftp-downloads/report.csv
sftp> bye
$ test -s "$HOME/sftp-downloads/report.csv" && echo 'download exists and is non-empty'
download exists and is non-empty
Use your actual local home path instead of /home/LOCAL_USER. Omit the local destination and get report.csv writes a same-named file into your current local directory, so check lpwd first if that default would surprise you.
Safety warning
Downloading to an existing path can replace its contents. Choose a new name, or back up first, when the destination matters. There is no shell redirection involved here, so do not add one to an SFTP command.
4. Upload a file without changing the original
Use lcd to pick the local directory, then put to send a file to a known remote name:
$ sftp [email protected]
sftp> lcd /home/LOCAL_USER/outgoing
sftp> lpwd
Local working directory: /home/LOCAL_USER/outgoing
sftp> put package.tar.gz /remote/path/package.tar.gz
Uploading package.tar.gz to /remote/path/package.tar.gz
sftp> ls -l /remote/path/package.tar.gz
sftp> bye
put reads the local file and writes the remote destination; it never deletes or moves the local original. If the remote name already exists, treat overwriting it as a destructive action: pick a new name, or ask the remote administrator how that destination is managed.
To upload a whole directory tree, add -r to the client command or -R to the interactive put. SFTP does not follow symbolic links during recursive transfers. Check the target directory first, since a broad recursive upload can create more remote state than you meant to.
5. Resume an interrupted transfer carefully
Only resume when you actually know the partial file belongs to this transfer. The client has no way to prove an existing partial file has the right contents:
$ sftp [email protected]
sftp> reget large.iso /home/LOCAL_USER/sftp-downloads/large.iso
Fetching /remote/path/large.iso to /home/LOCAL_USER/sftp-downloads/large.iso
sftp> bye
reget is equivalent to get -a; for an upload, use reput, equivalent to put -a. If the partial local and remote contents actually differ, the result can be a corrupt file. Remove or rename an untrusted partial file and do a fresh transfer instead.
A transfer can also run in batch mode, useful for a small, reviewed job. Put the commands in a file and use non-interactive authentication:
$ sftp -b ./download.sftp [email protected]
$ cat ./download.sftp
cd /remote/path
get report.csv /home/LOCAL_USER/sftp-downloads/report.csv
bye
Batch mode aborts when a command such as get, put, rm, mkdir or ls fails, so review the file before running it. Never put a password in the batch file, and remove a temporary batch file once you've checked its contents if it contains sensitive paths or host details.
6. Handle paths and options deliberately
Quote remote paths containing spaces, and escape glob characters when you mean a literal character rather than a pattern:
sftp> get "Quarterly report.csv" ./reports/
sftp> ls 'archive[2026].tar'
sftp> get archive\[2026\].tar ./reports/
For a non-standard SSH port, use the SFTP option -P with a capital letter, or pass the SSH configuration option explicitly:
$ sftp -P 2222 [email protected]
$ sftp -oPort=2222 [email protected]
-ppreserves modification times, access times and modes for transferred files. Use it only when keeping those attributes is actually part of the job.-qsuppresses progress and diagnostic messages, so leave it off while you are troubleshooting.-vraises logging detail, handy when authentication or connection setup fails.
7. Diagnose failures without escalating blindly
A permission error on a remote path is normally fixed by choosing a permitted path or asking the remote administrator, not by running local sftp with sudo. Elevation changes the local process and can change which SSH keys and configuration files it uses.
For connection diagnostics, retry with verbose logging:
$ sftp -v [email protected]
For a missing file, use pwd, lpwd and ls -l to pin down which side and directory you actually meant. For a failed batch transfer, run the same commands interactively first. For a rejected host key, stop and verify the host identity rather than deleting known-hosts entries out of reflex.
Done means
- You checked the installed
sftpbinary and OpenSSH client version. - You verified the host key before accepting a first connection.
- You can tell apart
pwdfromlpwd, and remote paths from local paths. - You downloaded and uploaded using explicit destinations, leaving the local source intact.
- You only resumed a transfer once the partial file was trustworthy.
- You know ordinary transfers need no
sudo, and you have not used it to bypass remote permissions.