Transferring Files (scp & rsync)
Sooner or later you will need to move files between your laptop and a server: pushing a website you built, pulling down a log file, or deploying a whole folder. Both scp and rsync do this over SSH (Secure Shell — the encrypted protocol you already use to log into servers), so your files travel safely across the network. The difference is how they copy: scp blindly copies everything every time, while rsync is smart and only sends the parts that changed. This page shows you both, and explains exactly when each one is the right tool.
What scp is and when to use it
scp stands for “secure copy”. It copies files from one machine to another over an SSH connection. It is built into the OpenSSH client, so if you can ssh into a server, you already have scp.
scp is best for one-off, simple copies: a single file or a small folder you just need to get from A to B once. It has almost no options to learn, which makes it quick for quick jobs.
Note: On modern Ubuntu (22.04 / 24.04 LTS),
scpuses the SFTP protocol under the hood by default instead of the old legacyscpprotocol. The commands below are unchanged, but transfers are safer and more reliable than they were on older systems.
Copying a file to a server
The pattern is always scp SOURCE DESTINATION. A remote location is written as user@host:/path.
scp ./report.pdf [email protected]:/home/deploy/uploads/
Output:
report.pdf 100% 2048KB 4.1MB/s 00:00
Copying a file from a server to your machine
Just swap the order. The remote side is the source, and . means “my current directory”.
scp [email protected]:/var/log/nginx/error.log .
Output:
error.log 100% 18KB 120.4KB/s 00:00
Copying a whole folder
By default scp refuses to copy directories. Add -r (recursive) to include everything inside.
scp -r ./mysite [email protected]:/var/www/
If your server uses a non-standard SSH port, note that scp uses a capital -P for the port (regular ssh uses lowercase -p):
scp -P 2222 ./report.pdf [email protected]:/home/deploy/
What rsync is and when to use it
rsync (“remote sync”) also copies files over SSH, but it was designed for repeated transfers. The first time you run it, it copies everything. Every time after that, it compares the source and destination and sends only the differences — new files, changed files, and even just the changed bytes inside a large file. This is called delta transfer.
Install it on Ubuntu if it is not already present (it usually is):
sudo apt update
sudo apt install rsync
Use rsync when you will sync the same folder more than once, when you are deploying a website or app, when the files are large, or when your connection is slow or flaky and you need to be able to resume.
The flags you will use 90% of the time
The classic combination is -avz:
| Flag | Meaning | Why you want it |
|---|---|---|
-a | Archive mode | Copies recursively and preserves permissions, timestamps, and symlinks |
-v | Verbose | Prints each file as it transfers so you can see progress |
-z | Compress | Squeezes data during transfer — faster over slow networks |
--delete | Mirror | Deletes files on the destination that no longer exist in the source |
--dry-run | Preview | Shows what would happen without changing anything |
--progress | Per-file bar | Shows a live progress bar for each file |
Deploying a folder to a server with rsync
Say you built a static website in a local folder called dist/ and want to push it to /var/www/mysite/ on your server.
rsync -avz --progress ./dist/ [email protected]:/var/www/mysite/
Output:
sending incremental file list
index.html
assets/app.css
assets/app.js
sent 41,204 bytes received 92 bytes 27,530.67 bytes/sec
total size is 38,901 speedup is 0.94
Gotcha: the trailing slash on the source matters.
./dist/(with a slash) copies the contents ofdistinto the target../dist(no slash) copies thedistfolder itself, creating/var/www/mysite/dist/. When in doubt, run with--dry-runfirst.
Run the exact same command again later, after you change one file, and rsync only sends that one file:
rsync -avz --progress ./dist/ [email protected]:/var/www/mysite/
Output:
sending incremental file list
index.html
sent 1,182 bytes received 38 bytes 2,440.00 bytes/sec
total size is 38,920 speedup is 31.90
Making the destination an exact mirror
If you deleted some old files locally and want the server to match exactly, add --delete. Without it, deleted files linger on the server forever.
rsync -avz --delete ./dist/ [email protected]:/var/www/mysite/
Warning:
--deletepermanently removes files on the destination. Always run it once with--dry-runadded so you can see what will be deleted before it actually happens.
Using a custom SSH port or key
rsync lets you pass any SSH option through the -e flag:
rsync -avz -e "ssh -p 2222 -i ~/.ssh/deploy_key" ./dist/ [email protected]:/var/www/mysite/
Resuming a big interrupted transfer
If a large transfer drops, add --partial so rsync keeps the half-copied file and continues from where it stopped next time, instead of starting over.
rsync -avz --partial --progress ./backup.tar.gz [email protected]:/home/deploy/
scp vs rsync — when to use which
| Situation | Best tool | Why |
|---|---|---|
| Copy one file, once | scp | Shortest command, nothing to learn |
| Deploy a website or app folder | rsync | Sends only changes, much faster on repeat |
| Re-sync the same folder regularly | rsync | Delta transfer skips unchanged files |
| Large files over a slow link | rsync | Compression plus resumable --partial |
| Need an exact mirror (remove stale files) | rsync --delete | scp cannot delete extra files |
| Server only has SSH, nothing extra installed | scp | Always present with OpenSSH |
The short rule: first copy, do it once — reach for scp. Copy it again and again — reach for rsync.
Best Practices
- Always test risky
rsyncruns with--dry-runfirst, especially anything using--delete. - Use SSH keys instead of passwords for transfers (see SSH key authentication) so scripts and deploys run without prompts.
- Mind the trailing slash on
rsyncsources — it changes whether you copy a folder or its contents. - Prefer
rsync -avzfor any deploy: archive mode preserves permissions and timestamps that a plain copy can mangle. - Never transfer secrets (like
.envfiles or private keys) into a publicly served folder such as/var/www. - For large or unreliable transfers, add
--partial --progressso you can resume and watch progress. - Combine
rsyncwith a non-standard SSH port using-e "ssh -p PORT"rather than guessing — it must match your server’s SSH config.