Hey folks, I'm documenting this on the go because I've lost count of how many times I've used scp in real production environments — deploying code to EC2 instances, pulling logs from staging servers, syncing config files between data centers, and even moving terabytes of data between remote hosts during migrations.

Whether you're a beginner who's just SSH'd into your first VPS or a pro scripting automated deployments, this guide covers everything about the scp (Secure Copy) command. I'll explain the why behind every option, give you copy-paste-ready examples, call out common gotchas I've debugged over the years, and keep everything in plain, crisp English. No fluff, just practical knowledge you can use today.

What is SCP and Why It Matters

scp is a command-line utility that securely copies files and directories between local and remote machines (or between two remote machines) over the SSH protocol.

Everything is encrypted end-to-end. Unlike cp, ftp, or rsync over plain HTTP, scp never sends your data or passwords in the clear. It re-uses your existing SSH authentication (password, key, or agent), which makes it dead simple yet extremely secure.

Real-world use cases where I reach for scp daily:

  • Push a new build artifact to production
  • Pull application logs for debugging
  • Sync configuration files between dev/staging/prod
  • Copy large datasets between two cloud providers (without downloading to my laptop first)
  • One-off file transfers during incident response

How it works under the hood (quick senior-dev explanation):
scp opens an SSH connection, authenticates, then uses either the legacy SCP protocol or (since OpenSSH 9.0+) the SFTP protocol internally. Data streams over the encrypted SSH tunnel. That's it. No extra server setup required.

Prerequisites (Don't Skip These)

  1. OpenSSH client installed (99% of Linux distros have it):
    # Ubuntu/Debian
    sudo apt update && sudo apt install openssh-client -y
    
    # RHEL/CentOS/Fedora
    sudo dnf install openssh-clients -y
    
  2. SSH access to the remote host(s) — you should be able to do ssh user@remotehost successfully.
  3. Proper file permissions on the remote side (usually 644 for files, 755 for dirs).
  4. Firewall allowing SSH port (default 22).

Basic Syntax (Memorize This)

scp [OPTIONS] SOURCE DESTINATION
  • SOURCE and DESTINATION can be:
    • Local path: /home/user/file.txt
    • Remote path: user@host:/path/to/file.txt

You can copy:

  • Local → Remote
  • Remote → Local
  • Remote → Remote

All Major Options (With When to Use Them)

Here's the cheat-sheet I keep in my notes:

Option Meaning When I use it Example value
-r Recursive (dirs + contents) Copying folders -r
-P Remote SSH port (uppercase!) Non-standard ports -P 2222
-i Identity file (SSH key) Key-based auth (always in prod) -i ~/.ssh/id_rsa
-p Preserve timestamps/permissions Keep exact metadata -p
-C Compress data during transfer Slow networks, large text/log files -C
-l 1000 Limit bandwidth (Kbit/s) Don't saturate links -l 5000
-v Verbose (debug output) Troubleshooting -v
-q Quiet (no progress) Cron jobs/scripts -q
-B Batch mode (no password prompts) Automation -B
-3 Copy via local host (remote↔remote) Both remotes can't reach each other -3
-o Pass SSH options ProxyJump, StrictHostKeyChecking=no -o ProxyJump=bastion
-O Force legacy SCP protocol Old servers that don't support SFTP -O

Every Use Case with Sample Code

1. Copy Single File: Local → Remote (Most Common)

scp /home/bvkiran/app.log [email protected]:/var/log/myapp/

What happens: File is uploaded. You'll be prompted for password (or use key).

Pro tip: Want to rename on destination? Just change the destination filename:

scp app.log [email protected]:/var/log/myapp/newname.log

2. Copy Single File: Remote → Local

scp [email protected]:/var/log/myapp/error.log ./debug-error.log

Debug note: If you forget the local path, it copies to current directory with same name.

3. Copy Directory Recursively (Local → Remote)

scp -r /home/bvkiran/my-project/ [email protected]:/opt/apps/

Important: The trailing / on source means "copy contents of my-project". Without it, it copies the folder itself.

4. Copy Directory: Remote → Local

scp -r [email protected]:/var/backups/daily/ ./local-backups/

5. Copy Multiple Files & Wildcards

# All .log files
scp *.log deploy@server:/tmp/logs/

# Be careful with shell expansion — quote when in doubt
scp 'app-*.jar' deploy@server:/opt/deploy/

Gotcha I've debugged 100 times: If the remote path has wildcards, use -T (disable SFTP) or quote properly.

6. Copy Between Two Remote Hosts (Remote → Remote)

scp user1@host1:/data/bigfile.tar.gz user2@host2:/backup/

Advanced: If host1 and host2 cannot reach each other directly (firewall/VPC), force copy via your local machine:

scp -3 user1@host1:/data/bigfile.tar.gz user2@host2:/backup/

Data flows: host1 → your laptop → host2. Slower but works.

7. Using a Non-Standard SSH Port

scp -P 2222 /local/file.txt [email protected]:/tmp/

Note: -P is uppercase. -p is preserve. I still mix them up sometimes.

8. Using SSH Private Key (Production Standard)

scp -i ~/.ssh/prod_key.pem /build/app.jar ec2-user@aws-prod:/home/ec2-user/

Best practice: Add key to ~/.ssh/config so you never type -i again (see below).

9. Preserve Timestamps & Permissions

scp -p -r /important/configs/ root@backup-server:/backups/

Keeps original modification time and permissions — critical for backups.

10. Compress During Transfer (Great for Logs)

scp -C -r /var/log/nginx/ admin@remote:/backup/nginx-$(date +%F)/

Compression happens on the fly. Huge win on slow connections.

11. Limit Bandwidth (Don't Kill the Network)

scp -l 8000 -r /large-dataset/ user@server:/data/

(8000 Kbit/s = ~1 MB/s)

12. Verbose Mode – Your Best Friend for Debugging

scp -v -r myfolder/ user@host:/tmp/

You'll see every SSH handshake step. Use this when you get "Permission denied" or "Connection refused".

13. Quiet Mode + Batch for Scripts/Cron

scp -q -B -i /root/.ssh/id_rsa /backup.sql user@db-server:/backups/

No output, no password prompt — perfect for automation.

14. Using SSH Config Aliases (My Daily Driver)

Create ~/.ssh/config:

Host prod
    HostName production.example.com
    User deploy
    Port 2222
    IdentityFile ~/.ssh/prod_key.pem

Host staging
    HostName staging.example.com
    User deploy

Now commands become beautiful:

scp -r new-build/ prod:/opt/app/
scp error.log staging:/tmp/

15. Pass Extra SSH Options (ProxyJump / Jump Hosts)

scp -o ProxyJump=bastion-server /file.txt internal-server:/tmp/

Or inline:

scp -J [email protected] /file.txt [email protected]:/tmp/

Security Best Practices (Senior Dev Edition)

  • Never use passwords in scripts → always SSH keys.
  • chmod 600 ~/.ssh/id_* and chmod 700 ~/.ssh/.
  • Use ssh-agent so you don't keep typing passphrases.
  • Disable password auth on production servers.
  • Prefer key-based auth + ssh-config.
  • For extremely sensitive data: consider gpg encryption first, then scp.

Common Errors & How I Fix Them (Debug Section)

  1. Permission denied
    → Check SSH key, remote user permissions, ~/.ssh/authorized_keys perms (must be 600).

  2. Connection refused / timed out
    → Wrong port? Firewall? Server down? Try ssh -v user@host first.

  3. scp: error: unexpected filename
    → Wildcard expansion issue. Use quotes or -T.

  4. No such file or directory
    → Path typo. Use full absolute paths on remote.

  5. Slow transfer
    → Add -C, reduce -l, or switch to rsync for large dirs.

  6. Host key verification failed
    ssh-keygen -R hostname to remove old key.

  7. Interrupted transfer
    scp has no resume. Use rsync instead for resumable transfers.

When NOT to Use SCP (Honest Advice)

  • Large directories with many small files → use rsync -avz (delta transfer).
  • Need to resume interrupted transfers → rsync.
  • Interactive browsing → use sftp or rsync --progress.
  • Need to exclude files → rsync --exclude.

Quick Reference Cheat Sheet

# Most used one-liners I type daily
scp -r -C local-dir/ user@host:/dest/
scp -i key.pem -P 2222 file.txt user@host:/tmp/
scp -3 host1:file host2:/backup/

That's it. You've now got the complete picture — from zero to production-ready scp mastery.