Networking and remote
scp
Copy files between hosts over ssh, with cp-like syntax where a remote path is written HOST:PATH.
scp [OPTION...] SOURCE... TARGET (either side may be [USER@]HOST:PATH)
scp is cp across machines: scp file host:dir/ uploads, scp host:file . downloads.
It uses the same connection, keys and ~/.ssh/config as ssh, so if ssh host works,
scp works too. A path after the colon is relative to your home directory on the remote host;
start it with / for an absolute path.
scp always copies everything it is given. For repeated copies of a directory, or anything big
enough that an interrupted transfer would hurt, rsync is better: it sends only what
changed and can resume. For a quick one-off file, scp is the shortest command.
Since OpenSSH 9.0, scp talks the SFTP protocol under the hood instead of the old rcp-style
protocol. You rarely notice, except that remote wildcards are expanded by scp itself rather
than by the remote shell. -O switches back to the legacy protocol for very old servers. In
these examples the remote host server is the sandbox itself, so remote paths land in
/home/dev.
Examples
Copy a file to a remote host
scp todo.txt server:/tmp/
ssh server 'ls -l /tmp/todo.txt'
-rw-rw-r-- 1 dev dev 62 Oct 31 20:20 /tmp/todo.txt
server:/tmp/ is a directory on the remote host, so the file keeps its name there. scp
prints nothing here because its output is not a terminal; interactively it shows a
progress bar.
Copy a file from a remote host
scp server:demo/data/hosts.txt ./hosts-copy.txt
cat hosts-copy.txt
web01 10.0.0.11 web02 10.0.0.12 db01 10.0.0.21 cache01 10.0.0.31
demo/data/hosts.txt is relative to your home directory on the remote side. The local
target gives the copy a new name.
Copy several files into a remote directory
Setup run before this example
ssh server 'mkdir -p uploads'scp notes.txt todo.txt README.md server:uploads/
ssh server 'ls uploads'
README.md notes.txt todo.txt
As with cp, the last argument is the target and every other one is copied into it. The
remote directory has to exist.
Copy a directory with -r
scp -r src server:src-copy
ssh server 'find src-copy -type f | sort'
src-copy/Makefile src-copy/app.py src-copy/lib/helpers.py src-copy/main.c src-copy/util.sh
-r copies the whole tree. Because src-copy did not exist, the copy of src is created
under that name; had it existed, the tree would have gone inside it as src-copy/src.
Keep modification times with -p
scp access.log server:/tmp/plain.log
scp -p access.log server:/tmp/kept.log
ssh server 'ls -l --time-style=+%F /tmp/*.log'
-rw-rw-r-- 1 dev dev 2309 2026-10-24 /tmp/kept.log -rw-rw-r-- 1 dev dev 2309 2026-10-31 /tmp/plain.log
A plain copy gets the current time; -p preserves the original modification time (and
access time and mode), so the copy shows the same date as access.log.
Copy remote files matching a pattern
mkdir fetched
scp 'server:demo/logs/*.log' fetched/
ls fetched
app.log error.log
Quote the remote pattern so your local shell leaves it alone; scp expands it on the remote
side. app.log.1 does not end in .log and is skipped.
Use a different port with -P
scp -P 22 todo.txt server:/tmp/
echo "copied, exit $?"
copied, exit 0
scp's port option is a capital -P (lowercase -p means preserve). Port 22 is the default
anyway; use this for servers listening elsewhere, or set Port in ~/.ssh/config.
Use a host alias from an ssh config
Host backup
HostName 127.0.0.1
User dev
scp -F ssh_config data/sales.csv backup:/tmp/
ssh server 'wc -l /tmp/sales.csv'
13 /tmp/sales.csv
Every setting from the ssh configuration applies to scp: here the alias backup resolves
to an address and user. In everyday use the block lives in ~/.ssh/config and -F is not
needed.
A remote file that does not exist
scp server:nope.txt .
scp: nope.txt: No such file or directory
scp reports the missing remote path and exits with 1. Nothing is created locally.
Common pitfalls
scp file host(no colon) makes a local copy namedhost. The colon is what makes a path remote.-Pis the port and-pis preserve, the opposite of ssh's-pport.scp re-sends whole files every time and cannot resume. For large or repeated transfers use
rsync -aP.File names with spaces on the remote side: since OpenSSH 9.0 (SFTP mode)
scp 'host:my file.txt' .works as written; with-O(legacy mode) the remote shell splits the name and you need extra quoting.
GNU vs BSD and macOS
The examples above ran the GNU/Linux version. These are the differences that matter on macOS and the BSDs (written from their documentation, not run here).
All platforms use OpenSSH's scp. Versions before 9.0 (common on older servers and macOS releases) use the legacy protocol by default, where remote wildcards and quoting are handled by the remote shell.
Options worth knowing
A selection, described in our own words. For the full list, see scp(1) or scp --help.
| Option | What it does |
|---|---|
-r | Copy directories recursively. |
-p | Preserve modification and access times and modes. |
-P PORT | Connect to PORT on the remote host. |
-i FILE | Use the private key in FILE. |
-F FILE | Use FILE as the ssh configuration. |
-o OPTION | Pass an ssh option, for example -o ConnectTimeout=5. |
-q | Quiet: no progress meter or warnings. |
-v | Print ssh debug messages. |
-C | Compress the transfer. |
-l KBITS | Limit bandwidth in Kbit/s. |
-J [USER@]HOST[:PORT] | Connect through a jump host. |
-3 | Copy between two remote hosts through the local machine. |
-O | Use the legacy SCP protocol instead of SFTP. |
-s | Use the SFTP protocol (the default in OpenSSH 9.0 and later). |
-4 | Use IPv4 only. |
-6 | Use IPv6 only. |
Related
sshLog in to a remote machine or run a command on it over an encrypted connection; also forwards ports and jumps through hosts.rsyncCopy and synchronize files and directories, locally or over ssh, transferring only what changed.cpCopy files and directories, optionally keeping their timestamps, permissions and links.tarBundle files and directories into one archive, list it, or extract it; optionally compressed with gzip, bzip2, xz or zstd.