SSH and SCP Explained: Secure Remote Access and File Transfer for Beginners
Every time a developer deploys code to a production server, backs up a database, or fixes a bug on a remote machine at 2am, there's one tool quietly making it possible: SSH. It's the backbone of modern DevOps, cloud computing, and Linux server management. If you're getting into any of those fields — or just want to stop being afraid of the terminal — SSH is the single most important skill to learn first.
Before SSH existed, people used tools like Telnet to connect to remote machines. The problem? Everything — including your password — was sent across the network as plain text. Anyone sniffing the network traffic could read it. SSH (Secure Shell) solved this by encrypting the entire connection. It's the difference between shouting your bank PIN across a crowded room and whispering it through a private encrypted tunnel that only you and the server can decode. SCP (Secure Copy Protocol) builds on that same tunnel to let you copy files between machines, so you're never transferring sensitive data in the open.
By the end of this article you'll know exactly how SSH works and why it's secure, how to connect to a remote Linux server from your terminal, how to set up SSH key-based authentication so you never type a password again, and how to use SCP to send and receive files like a pro. You'll also avoid the most common beginner mistakes that cause frustrating 'Permission denied' errors.
How SSH Works: The Locked Door and the Secret Handshake
SSH uses a concept called public-key cryptography. Think of it like a padlock you can hand out freely to anyone. You keep the key to that padlock completely private. Someone can lock a box using your padlock (encrypt data with your public key), but only you can open it (decrypt it with your private key). This is the core idea behind SSH keys.
When you connect to a server over SSH, here's what actually happens in the background:
- Your client and the server agree on an encryption algorithm.
- The server proves its identity to you using its own key (this prevents 'man-in-the-middle' attacks where someone pretends to be your server).
- A unique session key is created just for this connection.
- All traffic from that point on is encrypted with that session key.
You authenticate using either a password (convenient but weaker) or an SSH key pair (a private key on your machine + a public key on the server). Key-based auth is what every professional uses because it's both more secure and more convenient — no typing passwords, and automated scripts can connect without human input.
The default port for SSH is 22. When you hear someone say 'open port 22 in the firewall', this is what they mean.
# ───────────────────────────────────────────────────────────── # BASIC SSH CONNECTION # Syntax: ssh [username]@[server-address] # ───────────────────────────────────────────────────────────── # Connect to a remote server as user 'deploy' at IP 203.0.113.42 # SSH will prompt for the user's password if no key is configured ssh deploy@203.0.113.42 # ───────────────────────────────────────────────────────────── # CONNECT ON A NON-STANDARD PORT # Some servers move SSH off port 22 for security (obscurity). # Use the -p flag to specify a different port. # ───────────────────────────────────────────────────────────── ssh -p 2222 deploy@203.0.113.42 # ───────────────────────────────────────────────────────────── # RUN A SINGLE COMMAND ON THE REMOTE SERVER WITHOUT STAYING LOGGED IN # Useful in scripts — connect, run the command, disconnect immediately. # Here we're checking available disk space on the remote machine. # ───────────────────────────────────────────────────────────── ssh deploy@203.0.113.42 'df -h /' # ───────────────────────────────────────────────────────────── # VERBOSE MODE — use -v to see exactly what SSH is doing # Invaluable for debugging connection failures # ───────────────────────────────────────────────────────────── ssh -v deploy@203.0.113.42
The authenticity of host '203.0.113.42 (203.0.113.42)' can't be established.
ED25519 key fingerprint is SHA256:abc123XYZexampleFingerprint.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '203.0.113.42' (ED25519) to the list of known hosts.
deploy@203.0.113.42's password:
Welcome to Ubuntu 22.04.3 LTS (GNU/Linux 5.15.0-91-generic x86_64)
deploy@web-server-01:~$
# After running: ssh deploy@203.0.113.42 'df -h /'
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 50G 18G 30G 38% /
SSH Key Authentication: Ditch the Password Forever
Password authentication works, but it has real problems. Passwords can be brute-forced, forgotten, or accidentally logged. SSH keys are essentially a 4096-bit random string — impossible to guess. And once they're set up, connecting feels like magic: you just type ssh deploy@yourserver.com and you're in.
Here's how key-based auth works: - You generate a key pair: a private key (stays on your laptop, never shared) and a public key (copied to the server). - When you connect, SSH uses cryptographic math to prove you possess the private key without ever transmitting it. - The server confirms the proof matches the public key it has stored for you.
Your private key lives in ~/.ssh/id_ed25519 (or id_rsa for older RSA keys). Your public key is ~/.ssh/id_ed25519.pub. The .pub file is the one you share freely. The private key file is the one you protect like a password — in fact, you can add an extra passphrase to it for a second layer of security.
ED25519 is the modern algorithm to use. It's faster and more secure than the older RSA algorithm. If you see old tutorials using ssh-keygen -t rsa, you can safely prefer ED25519 instead.
# ───────────────────────────────────────────────────────────── # STEP 1: GENERATE AN SSH KEY PAIR ON YOUR LOCAL MACHINE # -t ed25519 : use the modern ED25519 algorithm # -C : attach a comment so you know which key is which # This creates two files: # ~/.ssh/id_ed25519 (PRIVATE key — never share this) # ~/.ssh/id_ed25519.pub (PUBLIC key — copy this to servers) # ───────────────────────────────────────────────────────────── ssh-keygen -t ed25519 -C "alice@mycompany.com" # You'll be prompted: # Enter file in which to save the key (/home/alice/.ssh/id_ed25519): [press Enter] # Enter passphrase (empty for no passphrase): [type a strong passphrase or press Enter] # ───────────────────────────────────────────────────────────── # STEP 2: COPY YOUR PUBLIC KEY TO THE REMOTE SERVER # ssh-copy-id handles this safely — it appends your public key # to ~/.ssh/authorized_keys on the server. # The server will look at authorized_keys to decide who can log in. # ───────────────────────────────────────────────────────────── ssh-copy-id -i ~/.ssh/id_ed25519.pub deploy@203.0.113.42 # ───────────────────────────────────────────────────────────── # STEP 3: TEST THE KEY-BASED CONNECTION # If setup is correct, you'll connect without being asked for a password. # ───────────────────────────────────────────────────────────── ssh deploy@203.0.113.42 # ───────────────────────────────────────────────────────────── # BONUS: IF ssh-copy-id ISN'T AVAILABLE (e.g. on Windows or minimal systems) # Manually append your public key to the server's authorized_keys file. # This does the same thing as ssh-copy-id in one piped command. # ───────────────────────────────────────────────────────────── cat ~/.ssh/id_ed25519.pub | ssh deploy@203.0.113.42 \ 'mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys' # ───────────────────────────────────────────────────────────── # VIEW YOUR PUBLIC KEY (safe to copy-paste anywhere) # ───────────────────────────────────────────────────────────── cat ~/.ssh/id_ed25519.pub
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/alice/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/alice/.ssh/id_ed25519
Your public key has been saved in /home/alice/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:Zd8Kp3mNexampleFingerprint alice@mycompany.com
The key's randomart image is:
+--[ED25519 256]--+
| .+o. |
| o+* |
+----[SHA256]-----+
# After running ssh-copy-id:
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/alice/.ssh/id_ed25519.pub"
deploy@203.0.113.42's password:
Number of key(s) added: 1
Now try logging into the machine with: ssh 'deploy@203.0.113.42'
# After running ssh deploy@203.0.113.42 (key-based — no password prompt!):
Welcome to Ubuntu 22.04.3 LTS
deploy@web-server-01:~$
# After running cat ~/.ssh/id_ed25519.pub:
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIExamplePublicKeyDataHere alice@mycompany.com
SCP: Copying Files Over SSH Like a Pro
SCP (Secure Copy Protocol) uses the SSH connection you already understand to copy files between machines. The syntax looks a bit odd at first, but once you see the pattern, it clicks immediately.
The golden rule of SCP syntax: scp [source] [destination]. For remote paths, you prefix them with username@host:. That colon is the signal that says 'this path is on a remote machine'.
So scp alice@server:/var/log/app.log ./ means: copy the file /var/log/app.log from the remote server (as user alice) to my current local directory. And scp ./backup.tar.gz alice@server:/tmp/ means: copy my local backup.tar.gz file up to the /tmp/ directory on the remote server.
SCP preserves file permissions and timestamps by default when you use the -p flag. For entire directories, add -r (recursive) — just like cp -r for local copies.
One thing to know: SCP is being quietly deprecated on some modern systems in favour of rsync or sftp for large transfers, because those have better progress reporting and can resume interrupted transfers. But SCP is still everywhere, still reliable for one-off file transfers, and still the tool you'll use and see most often as a beginner.
# ───────────────────────────────────────────────────────────── # SCP SYNTAX PATTERN: # scp [options] [source] [destination] # Remote path format: username@hostname:/path/to/file # ───────────────────────────────────────────────────────────── # ── UPLOAD: Copy a local file TO a remote server ───────────── # Copy a compiled app package from your local machine # up to the /var/www/releases/ directory on the production server scp ./myapp-v2.1.0.tar.gz deploy@203.0.113.42:/var/www/releases/ # ── DOWNLOAD: Copy a file FROM a remote server to your machine ── # Pull today's application log file from the server # into your current local directory (./ means here) scp deploy@203.0.113.42:/var/log/myapp/app-2024-01-15.log ./ # ── RECURSIVE: Copy an entire directory ────────────────────── # -r means recursive (copy the folder and everything inside it) # Upload a whole config directory to the server scp -r ./nginx-configs/ deploy@203.0.113.42:/etc/nginx/sites-available/ # ── PRESERVE PERMISSIONS AND TIMESTAMPS ────────────────────── # -p preserves the original file's modification time and permissions # Useful when timestamps matter (e.g. log rotation scripts) scp -p ./database-backup.sql deploy@203.0.113.42:/backups/ # ── SPECIFY A CUSTOM SSH KEY ────────────────────────────────── # If you have multiple keys, tell SCP which identity file to use # -i points to your private key scp -i ~/.ssh/id_ed25519 ./config.yaml deploy@203.0.113.42:/app/config/ # ── NON-STANDARD PORT ───────────────────────────────────────── # NOTE: SCP uses capital -P for port (unlike SSH which uses lowercase -p) # This is one of the most common beginner typos! scp -P 2222 ./deploy.sh deploy@203.0.113.42:/opt/scripts/ # ── COPY BETWEEN TWO REMOTE SERVERS (from your local machine) ─ # Your machine acts as the coordinator. # Copy a file from server-A directly to server-B. scp deploy@server-a.example.com:/var/exports/data.csv \ deploy@server-b.example.com:/var/imports/ # ── SHOW PROGRESS FOR LARGE FILES ──────────────────────────── # -v (verbose) shows progress detail # For a cleaner progress bar, use: rsync --progress (see Pro Tip below) scp -v ./large-video-export.mp4 deploy@203.0.113.42:/media/uploads/
myapp-v2.1.0.tar.gz 100% 4823KB 3.2MB/s 00:01
# After running the download command:
app-2024-01-15.log 100% 1247KB 2.1MB/s 00:00
# After running the recursive directory copy:
nginx-default.conf 100% 2KB 1.8MB/s 00:00
nginx-ssl.conf 100% 4KB 2.0MB/s 00:00
nginx-proxy.conf 100% 1KB 1.5MB/s 00:00
# After running the non-standard port command:
deploy.sh 100% 512 0.5MB/s 00:00
# Typical error if you forget the capital -P with SCP:
ssh: connect to host 203.0.113.42 port 22: Connection refused
lost connection
| Feature / Aspect | SSH (Secure Shell) | SCP (Secure Copy Protocol) |
|---|---|---|
| Primary purpose | Interactive remote terminal access | Non-interactive file transfer between machines |
| Protocol layer | Encrypted tunnel (SSH protocol) | Runs on top of the SSH protocol |
| Authentication method | Password or SSH key pair | Same as SSH — shares its auth mechanism |
| Port used | 22 (default) | 22 (default — same as SSH) |
| Transfers files? | No — use SCP or rsync for files | Yes — that is its entire purpose |
| Runs remote commands? | Yes — interactive shell or single commands | No — file transfer only |
| Recursive directory copy | N/A (not its job) | Yes — use the -r flag |
| Resume interrupted transfer | N/A | No — use rsync for resumable transfers |
| Port flag | Lowercase -p (e.g. -p 2222) | Uppercase -P (e.g. -P 2222) |
| Best used when | You need a shell session on a remote server | You need to quickly copy a file to/from a server |
| Modern alternative | Still the gold standard | rsync or sftp for large/resumable transfers |
🎯 Key Takeaways
- SSH encrypts your entire connection using public-key cryptography — your password or private key is never transmitted across the network in readable form.
- SSH key pairs work like a padlock you give out freely (public key on the server) and a unique key only you hold (private key on your machine) — the math proves you own the key without revealing it.
- SCP uses capital -P for port and lowercase -p for preserving file attributes — the exact opposite of SSH, which uses lowercase -p for port. This trips up everyone the first time.
- Incorrect file permissions on ~/.ssh/ (should be 700) or ~/.ssh/authorized_keys (should be 600) silently break key-based auth — SSH ignores key files that are too permissive as a security measure.
⚠ Common Mistakes to Avoid
- ✕Mistake 1: Wrong file permissions on ~/.ssh/ directory or authorized_keys — Symptom: SSH falls back to asking for a password even after you've set up keys, or gives 'Permission denied (publickey)' — Fix: SSH is paranoid about permissions for security. Run
chmod 700 ~/.sshandchmod 600 ~/.ssh/authorized_keyson the SERVER. If your private key file is too open, also runchmod 600 ~/.ssh/id_ed25519on your LOCAL machine. SSH silently ignores key files with overly permissive permissions. - ✕Mistake 2: Using lowercase -p instead of uppercase -P with SCP — Symptom: SCP ignores the port number and tries port 22, giving 'Connection refused' on servers running SSH on a different port — Fix: Always use capital
-Pfor port in SCP commands (e.g.scp -P 2222 ...). Remember the mnemonic: SCP uses lowercase-pfor 'preserve', so Port had to become uppercase. SSH is the opposite. - ✕Mistake 3: Forgetting the colon (:) in SCP remote paths — Symptom: Instead of copying from a remote server, SCP silently creates a local file or directory named literally 'user@host/path/to/file' in your current directory — Fix: The colon is what tells SCP 'this is a remote path'.
scp deploy@server /tmp/file ./(missing colon) is wrong.scp deploy@server:/tmp/file ./(with colon) is correct. Always double-check your SCP commands have that colon immediately after the hostname.
Interview Questions on This Topic
- QWhat is the difference between SSH password authentication and SSH key-based authentication, and why would you prefer one over the other in a production environment?
- QIf you run `ssh-copy-id` to set up key authentication but SSH still asks for a password, what would you check first and why?
- QA junior developer accidentally runs `chmod 777 ~/.ssh` on their server and now their SSH keys don't work. Can you explain why that broke things, and what they should do to fix it?
Frequently Asked Questions
What is the difference between SSH and SCP?
SSH (Secure Shell) gives you an interactive terminal session on a remote machine — you log in and run commands as if you were sitting at that server. SCP (Secure Copy Protocol) uses the SSH connection purely to transfer files between machines. You'd use SSH to manage a server and SCP to copy a config file or log from it.
Is it safe to share my SSH public key?
Yes, completely. Your public key (the .pub file) is designed to be shared. It's the 'padlock' — anyone can have a copy. What you must never share is your private key (the file without .pub extension). If your private key is compromised, an attacker can impersonate you on every server that has your public key in its authorized_keys file. Treat the private key exactly like a password.
What is the ~/.ssh/known_hosts file for?
It's SSH's memory of servers you've connected to before. The first time you connect to a server, SSH saves a fingerprint of that server's identity. Every subsequent connection, SSH checks the fingerprint still matches. If it doesn't match (which could mean the server was rebuilt, or someone is intercepting your connection), SSH refuses to connect and warns you loudly. This protects you from man-in-the-middle attacks.
Written and reviewed by senior developers with real-world experience across enterprise, startup and open-source projects. Every article on TheCodeForge is written to be clear, accurate and genuinely useful — not just SEO filler.