SSH, keys, scp & rsync
Connect securely, set up key-based login, use ~/.ssh/config and tunnels, and copy files with scp and rsync.
SSH (Secure Shell) is how you work on remote Linux machines: cloud servers, Raspberry Pis, the build box at work. It gives you an encrypted terminal session, secure file transfer, and tunnels to services that aren't exposed to the internet. In this lesson you'll connect to servers, set up key-based login, simplify everything with ~/.ssh/config, forward ports, and copy files with scp and rsync.
Connecting#
The client (ssh) comes with every Linux distribution and macOS, and with Windows 10/11. To accept connections, a machine needs the server (sshd): sudo apt install openssh-server on Ubuntu/Debian or sudo dnf install openssh-server on Fedora, then sudo systemctl enable --now ssh (the unit is sshd on Fedora/RHEL).
The first time you connect, SSH shows the server's host key fingerprint:
Answering yes stores it in ~/.ssh/known_hosts. If it ever changes, SSH refuses to connect with a big WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!. That means either the server was reinstalled, or someone is intercepting the connection. If you know it's a reinstall, remove the old entry with ssh-keygen -R server.example.com.
Leave a session with exit or Ctrl+D. If a connection hangs, type Enter ~ . to kill it.
Key-based authentication#
Passwords can be guessed and brute-forced. SSH keys are far stronger and more convenient. A key pair has two parts:
- a private key (
~/.ssh/id_ed25519) that stays on your machine and is secret; - a public key (
~/.ssh/id_ed25519.pub) that you put on every server you want to log in to.
1. Generate a key pair
(-N "" creates the key without a passphrase so this example runs non-interactively. For your real key, leave off -N and choose a passphrase when prompted; ssh-agent means you'll only type it once per session.) Ed25519 is the modern default: short, fast and secure. Use -t rsa -b 4096 only for very old systems.
Notice the permissions: the private key is 600 (only you can read it). SSH refuses to use private keys that others can read.
2. Copy the public key to the server
This appends your public key to ~/.ssh/authorized_keys on the server (and fixes its permissions). If ssh-copy-id isn't available, do it by hand:
Cloud providers (AWS, DigitalOcean, Hetzner...) let you paste your public key when you create a server, so it's there from the first boot.
3. Log in, with no password
ssh-agent: type your passphrase once
~/.ssh/config: stop typing long commands#
Create ~/.ssh/config (mode 600) to give hosts short names and default options:
Now ssh web1 is all you type, and ssh db hops through web1 automatically. scp, rsync, git and VS Code Remote-SSH all use these aliases too. You can check what SSH will actually use for a host with ssh -G web1:
Copying files: scp#
scp copies files over SSH, with the same syntax as cp plus host: prefixes:
Syncing files: rsync#
rsync is smarter: it only transfers what changed, can resume, preserves permissions and timestamps, and can delete files that disappeared from the source. It's the standard tool for deployments, backups and mirroring. Let's try it locally (it works the same over SSH):
The second run only copied the changed file, and --delete removed the file that no longer exists in the source. Over the network:
⚠️ The trailing slash matters.
rsync -a site/ dest/copies the contents ofsiteintodest.rsync -a site dest/createsdest/site/. Combined with--delete, getting this wrong can wipe a directory, so always do a dry run (-n) first.
Port forwarding (SSH tunnels)#
Local forwarding lets you reach a service that only listens on the server's localhost, such as a database, without opening it to the internet:
Remote forwarding does the reverse, exposing a port on your machine to the server: ssh -R 9000:localhost:3000 web1. Dynamic forwarding creates a SOCKS proxy: ssh -D 1080 web1.
Keeping long jobs alive#
If your connection drops, processes started in the session get SIGHUP and usually die. For long-running work, start tmux on the server first (tmux new -s deploy, detach with Ctrl+B D, reattach with tmux attach -t deploy). See the processes lesson for nohup and disown.
Server-side basics: sshd_config#
The SSH server is configured in /etc/ssh/sshd_config and drop-in files in /etc/ssh/sshd_config.d/*.conf (Ubuntu and Fedora both use the drop-in directory). Once your key login works, the two most important hardening settings are:
Always test the config and keep your current session open while you check that a new login still works:
More hardening (fail2ban, AllowUsers, changing ports) is covered in the security lesson.
Common mistakes#
- Wrong permissions on
~/.ssh. SSH silently ignores keys if~/.sshis not700,authorized_keysnot600, or your home directory is group-writable. Runssh -v hostto see why a key was rejected. - Sharing or copying private keys between people or laptops. Generate one key per person per device.
- No passphrase on a key that grants production access.
- Disabling password login before testing key login, and locking yourself out. Keep a second session open.
- Blindly typing
yesto a changed host key warning. - The rsync trailing-slash mix-up with
--delete. Dry-run first. scp -p 2222: scp's port flag is capital-P(lowercase-ppreserves times).
What's next#
Now that SSH is the front door to your servers, the next step is controlling what else can get in: firewalls with ufw (and firewalld on Fedora/RHEL).
Check your understanding
Quick quiz
1.With key-based SSH login, which file must stay secret?
2.What's the difference between
rsync -a src/ dest/andrsync -a src dest/?3.What does
ssh -L 5433:localhost:5432 ada@db.example.comdo?
Finished reading?
Mark this lesson complete to track your progress.