What you'll learn
Quick Answer
SSH gives you an encrypted shell on a remote machine. Authenticate with a key pair rather than a password — the public key goes on the server, the private key never leaves your machine.
How key authentication works
A key pair is two mathematically related files. The public key is safe to share and goes on servers. The private key stays on your machine and is never sent anywhere — not even during login.
Logging in, the server sends a challenge, your client signs it with the private key, and the server verifies that signature with the public key. Anyone watching the exchange learns nothing usable.
That is why keys beat passwords: a password is transmitted and can be guessed; a key is never transmitted and is far too large to guess.
ssh-keygen -t ed25519 -C "you@example.com"
Use ed25519 rather than RSA — it is shorter, faster and modern. You will be asked for a passphrase; set one. Without it, anyone who copies your private key file has your servers.
The passphrase is not typed on every connection if you use an agent:
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
Getting the key onto a server
ssh-copy-id deploy@example.com
That appends your public key to ~/.ssh/authorized_keys on the server with correct permissions. Where ssh-copy-id is unavailable, do it manually:
cat ~/.ssh/id_ed25519.pub | ssh deploy@example.com \
"mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys && \
chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys"
Those permissions are the single most common cause of "my key is not working". SSH deliberately refuses keys when the directory or file is readable by others, and the failure message rarely says so. If key login is silently falling back to a password prompt, check permissions first.
ssh -v shows the negotiation and usually names the problem directly, which beats guessing.
The config file nobody discovers early enough
Typing ssh -i ~/.ssh/project_key -p 2222 deploy@203.0.113.10 repeatedly is unnecessary. Put it in ~/.ssh/config:
Host prod
HostName 203.0.113.10
User deploy
Port 2222
IdentityFile ~/.ssh/project_key
Host *
ServerAliveInterval 60
AddKeysToAgent yes
Now ssh prod is the whole command. scp file prod:~/ works too, and so does anything else that uses SSH underneath — including git.
ServerAliveInterval stops idle connections being dropped by intermediate network equipment, which is the usual cause of a session freezing after a few minutes of inactivity.
This file is genuinely one of the highest-value things to set up once, and most people meet it years later than they should.
Copying files and tunnelling
scp report.pdf prod:~/uploads/ # copy to server
scp prod:~/logs/app.log ./ # copy from server
rsync -avz --progress ./dist/ prod:~/app/dist/ # sync a directory
rsync transfers only differences, resumes, and is far better for anything repeated.
Tunnelling is the feature worth knowing about, because it solves a real problem safely:
ssh -L 5433:localhost:5432 prod
That forwards your local port 5433 to port 5432 on the server, through the encrypted connection. You can now point a database client at localhost:5433 and reach the server's database — even though it is bound to localhost there and blocked by the firewall.
This is the correct way to reach a production database from your laptop. The wrong way is opening the database port to the internet, which is how databases get compromised. See setting up a Linux server.
Practical habits
- One key per device, not per server. Then losing a laptop means removing one public key everywhere, rather than untangling which key was where.
- Never copy a private key to a server. If a server needs to reach another machine, use agent forwarding cautiously or a separate deploy key. Copying your personal key onto a shared server means anyone with root there has it.
- Take the host key warning seriously. "REMOTE HOST IDENTIFICATION HAS CHANGED" usually means the server was rebuilt — but it is also exactly what an interception attack looks like. Verify before deleting the old entry.
- Use
tmuxorscreenfor long tasks, so a dropped connection does not kill a running migration. - Use keys for git too. The same key pair authenticates to GitHub, which removes password prompts on every push.
