Linux command list

scp command: copy files to and from a server

__ __ _ _____
\ \ / /__| |_|_ _|__ _ __ _ __ ___
\ \ /\ / / _ \ '_ \| |/ _ \ '__| '_ ` _ \
\ V V / __/ |_) | | __/ | | | | | |
\_/\_/ \___|_.__/|_|\___|_| |_| |_| |_
 
A sandbox for trying scp. Nothing here can touch your real files.
user@webterm:~/project$
 

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

Syntax

scp [options] source destination

The remote side is written as user@host:path.

Try it first

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.

Sending

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

Fetching

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.

Whole directories

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/

A different port

$ 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.

When you actually reach for it

scp is for moving a file between here and a server once.

SituationWhat to type
Ship a build to the serverscp app.tar.gz deploy@server:/home/deploy/
Pull a log backscp deploy@server:/var/log/app.log ./
Send a whole directoryscp -r dist deploy@server:/var/www/
Reach a non-standard portscp -P 2222 app.tar.gz deploy@server:/home/deploy/
Sync repeatedlyrsync -av dist/ deploy@server:/var/www/

Once for scp, repeatedly for rsync.

Things that trip people up

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 directory

Practise it hands-on

webterm.appthis site

  • Advanced Terminal Commands

    Learn commands for specific situations

    Try the tutorial

learn.webterm.appa separate site

>_WEBTERM LEARN

WebTerm Learn: from one command to actually using it

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

Related commands

ssh / rsync / ssh-keygen / tar

Frequently asked questions

How do sending and fetching differ?
Both are `scp source destination`. The remote side is written as `user@host:path`, so putting that on the right sends and putting it on the left fetches.
Why is the port flag different from ssh?
scp uses a capital `-P` while `ssh` uses a lowercase `-p`. It is a common slip.
It will not copy a directory.
Add `-r`. Without it you get `not a regular file`.
I get Permission denied (publickey).
scp travels over SSH, so key setup has to be done first. Get `ssh` working, and scp follows.
How does rsync compare?
scp sends everything every time. rsync sends only what changed, which matters when you sync a large directory repeatedly.