scp copies files over the SSH connection. Learn how sending and fetching are written, why directories need `-r`, and why the port flag is a capital `-P`, by running the commands in a real terminal in your browser.
Updated: 2026-09-11
scp [options] source destination
The remote side is written as user@host:path.
Without keys in place, nothing goes anywhere.
$ scp app.tar.gz deploy@server.example.com:/home/deploy/
deploy@server.example.com: Permission denied (publickey).
scp rides on SSH.
Making a key and handing over the public half is exactly the ssh procedure.
Pressing Enter at all three questions keeps the default location and no passphrase.
$ ssh-keygen -t ed25519
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/user/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/user/.ssh/id_ed25519
Your public key has been saved in /home/user/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:E4zOftaLf+dh7GxvLirKdf4udrfP+YfuPgkqepnXRuQ user@webterm
The key's randomart image is:
+--[ED25519 256]--+
| |
| o |
| . o |
| o . . |
| o S o |
| . o E. |
| . ooo+..+o |
| +=o++*+Oo=|
| .o+=o=o&XX@|
+----[SHA256]-----+
$ ssh-copy-id deploy@server.example.com
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/user/.ssh/id_ed25519.pub"
Number of key(s) added: 1
Now try logging into the machine, with: "ssh 'deploy@server.example.com'"
and check to make sure that only the key(s) you wanted were added.
Remote on the right means send.
$ scp app.tar.gz deploy@server.example.com:/home/deploy/
app.tar.gz 100% 8 0.0KB/s 00:00
The progress line means it went.
One remote ls confirms it arrived.
$ ssh deploy@server.example.com ls
app.tar.gz
Remote on the left means fetch.
$ scp deploy@server.example.com:/home/deploy/app.tar.gz downloaded.tar.gz
app.tar.gz 100% 8 0.0KB/s 00:00
$ ls
app.tar.gz config.yml dist/ downloaded.tar.gz
The order is always source then destination. Only the side the remote is on changes the direction.
Handed a directory, scp refuses.
$ scp dist deploy@server.example.com:/home/deploy/
dist: not a regular file
-r copies the contents.
$ scp -r dist deploy@server.example.com:/home/deploy/
index.html 100% 12 0.0KB/s 00:00
app.js 100% 15 0.0KB/s 00:00
$ ssh deploy@server.example.com ls
app.tar.gz dist/
$ scp -P 2222 config.yml deploy@server.example.com:/home/deploy/
config.yml 100% 11 0.0KB/s 00:00
A capital -P.
ssh uses a lowercase -p, and this is the one place they disagree.
scp is for moving a file between here and a server once.
| Situation | What to type |
|---|---|
| Ship a build to the server | scp app.tar.gz deploy@server:/home/deploy/ |
| Pull a log back | scp deploy@server:/var/log/app.log ./ |
| Send a whole directory | scp -r dist deploy@server:/var/www/ |
| Reach a non-standard port | scp -P 2222 app.tar.gz deploy@server:/home/deploy/ |
| Sync repeatedly | rsync -av dist/ deploy@server:/var/www/ |
Once for scp, repeatedly for rsync.
Forget the : and it is a local copy.
$ scp app.tar.gz deploy@server.example.com
app.tar.gz 100% 8 0.0KB/s 00:00
$ ls
app.tar.gz config.yml deploy@server.example.com dist/ downloaded.tar.gz
You now have a local file named deploy@server.example.com.
It looks like it was sent and it was not, so check the colon before pressing enter.
The port flag is a capital -P.
Lowercase -p means preserve timestamps, which is something else entirely.
Directories need -r.
A missing source says so.
$ scp nothing.txt deploy@server.example.com:/home/deploy/
nothing.txt: No such file or directorywebterm.appthis site
Advanced Terminal Commands
Learn commands for specific situations
learn.webterm.appa separate site

Commands stick when they show up in a real sequence of work, not one at a time. There is a course that builds them up in order.
See the course