How to transfer files to a server with SCP and SFTP
Copying files to and from a VPS with scp, sftp and rsync, and connecting a graphical tool like FileZilla when a terminal is not what you want.
A VPS has no built-in file manager reachable from outside it — every way of getting files on or off one rides over the same SSH connection you already use to log in. Which tool you reach for depends mostly on whether you want a single command, an ongoing sync, or a graphical window to drag files into.
scp: copy a file or folder, once
scp is the quickest option for a single file or a small set of them:
scp localfile.txt yourname@203.0.113.10:/home/yourname/
Copy a whole directory with -r:
scp -r localdirectory yourname@203.0.113.10:/home/yourname/
To go the other way, pulling a file down from the server:
scp yourname@203.0.113.10:/home/yourname/remotefile.txt ./
If SSH runs on a non-standard port, note that scp uses a capital -P for the port, unlike ssh's lowercase -p — a common source of a confusing "connection refused" the first time someone hits it:
scp -P 2222 localfile.txt yourname@203.0.113.10:/home/yourname/
sftp: an interactive session
For moving several files around interactively, without typing a full path on every command, open an SFTP session instead:
sftp yourname@203.0.113.10
Inside it, familiar-feeling commands work against the remote server:
ls # list remote files
lls # list local files
cd /var/www # change remote directory
lcd ~/Desktop # change local directory
put file.txt # upload
get file.txt # download
mput *.jpg # upload multiple files
exit
rsync: for anything you will repeat
Unlike scp, rsync only transfers what has actually changed, which makes it dramatically faster for repeated transfers of a mostly-unchanged directory — a website's files, or a nightly backup pull.
rsync -avz -e ssh /local/path/ yourname@203.0.113.10:/remote/path/
-a preserves permissions, ownership and timestamps; -v shows what it is doing; -z compresses data in transit. Note the trailing slash on the source path — /local/path/ copies the contents of the directory into the destination, while /local/path without it would create a path folder inside the destination instead. This distinction catches almost everyone at least once.
Adding --delete to an rsync command makes the destination an exact mirror of the source, removing anything at the destination that is not present at the source. That is exactly what you want for some jobs and exactly what destroys a week of untracked changes on others — always run with --dry-run first if you are not certain what it will remove.
rsync -avz --dry-run -e ssh /local/path/ yourname@203.0.113.10:/remote/path/
If SSH is on a non-standard port, pass it through the -e flag:
rsync -avz -e "ssh -p 2222" /local/path/ yourname@203.0.113.10:/remote/path/
Using a graphical client instead
If you would rather drag and drop than type commands, FileZilla, WinSCP and Cyberduck all support SFTP directly over your existing SSH login:
- Protocol
Choose SFTP — not FTP or FTPS, which are unrelated protocols the server is not running.
- Host
Your server's IP address or hostname.
- Port
22, unless you have moved SSH to a different port.
- Login type
Password, or point the client at your private key file if you use key-based login.
Speeding up a large transfer
For a large number of small files, compressing them into a single archive before transferring, then extracting on the other end, is often noticeably faster than transferring each file individually — every individual file over SSH carries its own small handshake overhead, which adds up quickly across thousands of files:
tar -czf archive.tar.gz /local/path/
scp archive.tar.gz yourname@203.0.113.10:/remote/path/
ssh yourname@203.0.113.10 "cd /remote/path && tar -xzf archive.tar.gz"
Resuming an interrupted transfer
A large transfer over an unreliable connection can drop partway through. rsync handles this far better than scp, since re-running the same command afterwards only transfers what did not complete the first time, rather than starting over from nothing:
rsync -avz --partial -e ssh /local/path/ yourname@203.0.113.10:/remote/path/
--partial keeps a partially transferred file rather than discarding it if the connection drops, so the next attempt can build on what already arrived instead of retransmitting it. For a transfer you expect might take a while and might need to survive a dropped connection, running it inside screen or tmux on the sending end also protects it from your own local connection interruption, not just the remote one.
A note on permissions
Files uploaded as one user belong to that user. If you upload as your personal sudo account but a web server running as a different user (commonly www-data or apache) needs to read or write them, you will need to adjust ownership afterwards:
sudo chown -R www-data:www-data /var/www/example.com
Get the transfer tooling comfortable and the same commands cover moving a whole site onto a new VPS — see moving from shared hosting to a VPS — or copying backups off the server on a schedule, covered in setting up automatic backups on a VPS.
Related reading
SSH is how you control a VPS from the command line, and setting it up properly the first time saves you a lot of trouble later.
How to set up automatic backups on a VPSA simple, scripted backup covering files and databases, scheduled with cron and copied off the server, plus how to actually test it.
How to move from shared hosting to a VPSBuilding the new server first and testing it privately before you touch DNS is what keeps this move from causing any visible downtime.
How much RAM does my VPS need?It depends what is running, but free -h on an existing server and a look at what each extra service costs gets you a real answer fast.