What is SCP?#
SCP (Secure Copy Protocol) transfers files between hosts over an SSH connection. It uses the same authentication and encryption as SSH, so if you can ssh into a machine, you can scp files to and from it.
scp file.txt user@remote:/path/to/destination/That’s the core pattern: scp <source> <destination>, where either side can be a remote host.
Basic Syntax#
scp [options] <source> <destination>Remote paths use the format user@host:/path. Local paths are just regular file paths.
| Direction | Command |
|---|---|
| Local → Remote | scp file.txt user@server:/tmp/ |
| Remote → Local | scp user@server:/tmp/file.txt ./ |
| Remote → Remote | scp user@server1:/tmp/file.txt user@server2:/tmp/ |
Key Options#
-r — Recursive (directories)#
Copy an entire directory and its contents:
scp -r ./project/ user@server:/home/user/project/Without -r, attempting to copy a directory will fail.
-P — Port#
Connect on a non-standard SSH port (note: uppercase -P, unlike ssh which uses lowercase -p):
scp -P 2222 file.txt user@server:/tmp/-i — Identity file#
Use a specific SSH private key:
scp -i ~/.ssh/deploy_key app.tar.gz user@server:/opt/releases/-C — Compression#
Compress data during transfer. Useful on slow connections with compressible data:
scp -C largefile.sql user@server:/backups/-l — Bandwidth limit#
Limit bandwidth in Kbit/s. Prevents saturating the connection:
# Limit to 5000 Kbit/s (~625 KB/s)
scp -l 5000 backup.tar.gz user@server:/backups/-q — Quiet mode#
Suppress the progress bar and non-error messages:
scp -q file.txt user@server:/tmp/-o — SSH options#
Pass any SSH configuration option directly:
scp -o StrictHostKeyChecking=no file.txt user@server:/tmp/Practical Examples#
Deploy a build artifact to a server#
scp -i ~/.ssh/deploy_key dist/app-v1.2.0.tar.gz deploy@prod:/opt/releases/Pull logs from a remote server#
scp user@server:/var/log/app/error.log ./error-$(date +%F).logCopy a directory to a remote host#
scp -r ./configs/ user@server:/etc/myapp/Transfer between two remote servers#
scp user@server1:/backups/db.sql.gz user@server2:/backups/Note: this routes traffic through your local machine by default. Both servers must be reachable from your workstation.
Use with SSH config aliases#
If your ~/.ssh/config defines a host:
Host prod
HostName 10.0.1.50
User deploy
IdentityFile ~/.ssh/deploy_key
Port 2222Then you can simply:
scp dist/app.tar.gz prod:/opt/releases/Copy multiple files#
scp file1.txt file2.txt user@server:/tmp/
# Or use a glob
scp *.log user@server:/backups/logs/Using Wildcards on Remote Paths#
To copy files matching a pattern from a remote host, quote the path to prevent local shell expansion:
scp user@server:"/var/log/app/*.log" ./logs/Without quotes, your local shell expands the * before SCP sees it.
Troubleshooting#
Permission denied#
# Check you can SSH to the host first
ssh user@server
# Verify the destination directory is writable
ssh user@server 'ls -ld /path/to/destination/'Connection refused or timeout#
# Test SSH connectivity
ssh -v user@server
# Verify the port
nc -zv server 22Slow transfers#
# Enable compression
scp -C largefile user@server:/tmp/
# Check if the bottleneck is network or disk
ssh user@server 'dd if=/dev/zero bs=1M count=100' | pv > /dev/nullHost key verification failed#
This usually means the server’s key changed (reinstall, IP reuse). Verify the change is expected, then:
ssh-keygen -R serverSCP vs Alternatives#
| Tool | Best For |
|---|---|
scp | Quick one-off transfers, simple syntax |
rsync | Incremental sync, resumable, better for large/repeated transfers |
sftp | Interactive file browsing, resume support |
ssh + tar | Preserving permissions/ownership, streaming directories |
For recurring or large transfers, rsync is generally preferred:
# rsync equivalent of scp -r
rsync -avz ./project/ user@server:/home/user/project/Best Practices#
- Use SSH keys instead of passwords for all SCP operations
- Prefer rsync for repeated or large transfers — it only sends differences
- Always quote remote wildcards to avoid local shell expansion
- Set up
~/.ssh/configaliases to avoid retyping hosts, ports, and key paths - Use
-lto limit bandwidth on shared or production connections - Verify transfers with checksums when integrity matters:
sha256sumon both sides

