Typing a password every time you connect is slow, and passwords can be guessed,
leaked, or brute-forced. Key-based authentication replaces the password with a
cryptographic key pair — faster to use, significantly harder to attack, and the
standard approach for any server you manage regularly. Once it's set up, connecting
feels like magic: you type ssh philip@server and you're in, no
password prompt at all.
How it works in one sentence: you generate a key pair, put the
public key on the server, and SSH proves your identity by signing a challenge
with your private key — the server verifies the signature without your private
key ever leaving your machine.
The Setup Flow
1
Generate a key pair on your local machine
Creates two files: ~/.ssh/id_ed25519 (private) and ~/.ssh/id_ed25519.pub (public). Runs on your machine only — nothing touches the server yet.
2
Copy your public key to the server
Use ssh-copy-id to append your public key to ~/.ssh/authorized_keys on the server. This step still uses your password — it's the last time you'll need it.
3
Test key-based login
Connect with ssh philip@server — if it works without asking for a password, keys are set up correctly.
4
Optionally: disable password authentication
Once keys work, disable password login on the server entirely. This eliminates brute-force attacks. Only do this after confirming key login works from a second terminal.
Step 1 — Generate Your Key Pair
Run this on your local machine — the one you're connecting
from. Use Ed25519 unless you specifically need RSA for an older server.
philip@debian — generate an Ed25519 key pair
philip@debian:~$ssh-keygen -t ed25519 -C "philip@debian"Generating public/private ed25519 key pair.Enter file in which to save the key (/home/philip/.ssh/id_ed25519):press Enter to accept defaultEnter passphrase (empty for no passphrase):recommended: enter a passphraseEnter same passphrase again:Your identification has been saved in /home/philip/.ssh/id_ed25519Your public key has been saved in /home/philip/.ssh/id_ed25519.pubThe key fingerprint is:SHA256:xyz789ABCdef123GHI456jklMNO philip@debianThe key's randomart image is:+--[ED25519 256]--+| .o+ || . o.o || . + + . |+----[SHA256]-----+
What the flags mean
-t ed25519 — use the Ed25519 algorithm (modern, fast, recommended).
-C "philip@debian" — a comment appended to the public key. Helps identify which machine a key came from when you have several. Use anything descriptive: your email, hostname, or purpose.
Should I set a passphrase?
Yes — and here's why. Your private key is just a file. If someone gets access
to your machine (stolen laptop, compromised account), they can use your private
key to connect to every server it's authorised on. A passphrase encrypts the key
file itself, so stealing the file alone is not enough.
The passphrase is only ever typed on your local machine — never sent over the
network. Use the SSH agent (below) so you only type it once per login session,
not on every connection.
Public Key — share freely
~/.ssh/id_ed25519.pub
Copy this to every server you want to access. It's safe to email, paste, or put in a GitHub profile. Begins with ssh-ed25519 AAAA...
Private Key — never share
~/.ssh/id_ed25519
Stays on your machine only. If you ever paste this somewhere, treat it as compromised and generate a new pair immediately. Begins with -----BEGIN OPENSSH PRIVATE KEY-----
Step 2 — Copy Your Public Key to the Server
The easy way: ssh-copy-id
ssh-copy-id handles everything — it connects to the server,
creates the ~/.ssh/ directory if needed, appends your public key
to authorized_keys, and sets the correct permissions. This is one
of the most useful commands in the SSH toolkit.
philip@debian — copy public key to server
philip@debian:~$ssh-copy-id philip@192.168.1.100/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/philip/.ssh/id_ed25519.pub"/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keysphilip@192.168.1.100's password:← last time you need the password
Number of key(s) added: 1
Now try logging into the machine, with: "ssh 'philip@192.168.1.100'"
and check to make sure that only the key(s) you wanted were added.
If you need to specify a key file or a non-standard port:
philip@debian — ssh-copy-id with options
# Specify a key file explicitlyphilip@debian:~$ssh-copy-id -i ~/.ssh/id_ed25519.pub philip@server# Server on a non-standard portphilip@debian:~$ssh-copy-id -p 2222 philip@server
The manual way — if ssh-copy-id isn't available
On Windows (before OpenSSH was built in) or on minimal systems,
ssh-copy-id may not be present. Do it manually:
philip@debian — manual key copy (one-liner)
# Pipe the public key into the server's authorized_keys in one commandphilip@debian:~$cat ~/.ssh/id_ed25519.pub | ssh philip@server \
"mkdir -p ~/.ssh && chmod 700 ~/.ssh && \
cat >> ~/.ssh/authorized_keys && \
chmod 600 ~/.ssh/authorized_keys"philip@server's password:
philip@debian:~$ssh philip@192.168.1.100(if key has a passphrase, you're prompted for it once — not the server password)Enter passphrase for key '/home/philip/.ssh/id_ed25519':Welcome to Debian GNU/Linux 12 (bookworm)philip@server:~$← in without typing the server password
If it still asks for the server password rather than the key passphrase, see
the troubleshooting section at the end of this chapter.
The SSH Agent — Type Your Passphrase Once
With a passphrase-protected key, you'd need to type the passphrase every time
you connect. The SSH agent solves this: it holds your decrypted key in memory
for the duration of your login session, so you type the passphrase once and
SSH silently uses it for every subsequent connection.
philip@debian — using the SSH agent
# Start the agent (usually already running on a Linux desktop)philip@debian:~$eval "$(ssh-agent -s)"Agent pid 12345# Add your key — type the passphrase once herephilip@debian:~$ssh-add ~/.ssh/id_ed25519Enter passphrase for /home/philip/.ssh/id_ed25519:Identity added: /home/philip/.ssh/id_ed25519 (philip@debian)# All subsequent connections use the cached key — no passphrase promptphilip@debian:~$ssh philip@serverphilip@server:~$← straight in, no prompt# List keys currently held by the agentphilip@debian:~$ssh-add -l256 SHA256:xyz789... /home/philip/.ssh/id_ed25519 (ED25519)
On most Linux desktops (GNOME, KDE, XFCE) the SSH agent starts
automatically when you log in and a keyring prompt handles the passphrase
transparently. On macOS, keys are stored in the system keychain. On Windows,
enable the "OpenSSH Authentication Agent" service in Services and set it to
start automatically.
What authorized_keys Looks Like
The authorized_keys file on the server contains one public key per
line. Multiple keys means multiple machines can connect — useful if you want both
your laptop and desktop to access the same server.
# ~/.ssh/authorized_keys on the SERVER# One public key per line — each grants access from the machine that holds the matching private key
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... philip@debian
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... philip@windows-laptop
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... philip@work-machine
You can also prefix a key with options to restrict what it can do:
# Restrict a key to only run one specific command (useful for automation)
command="backup.sh",no-pty,no-agent-forwarding ssh-ed25519 AAAAC3... backup@cronjob
# Restrict to connections from a specific IP only
from="192.168.1.50" ssh-ed25519 AAAAC3... philip@trusted-machine
Critical: File Permissions
SSH is paranoid about permissions — intentionally. If the ~/.ssh
directory or authorized_keys file is writable by anyone other than
you, SSH refuses to use them. This prevents another user on the same system from
injecting their own key into your file.
File / Directory
Required Permission
Owner
Why
~/.ssh/
700
you
Only you can read or write the directory
~/.ssh/authorized_keys
600
you
Only you can read or write the key list
~/.ssh/id_ed25519
600
you
Private key — only you should ever read it
~/.ssh/id_ed25519.pub
644
you
Public key — readable by others, no harm
~/.ssh/config
600
you
Config file — contains hostnames and settings
~/.ssh/ group/world writable
755 or 777
—
SSH will refuse to use authorized_keys entirely
philip@server — fix permissions if needed
philip@server:~$chmod 700 ~/.sshphilip@server:~$chmod 600 ~/.ssh/authorized_keysphilip@server:~$chmod 600 ~/.ssh/id_ed25519# Verifyphilip@server:~$ls -la ~/.ssh/drwx------ 2 philip philip 4096 Jun 17 20:00 .-rw------- 1 philip philip 571 Jun 17 20:00 authorized_keys-rw------- 1 philip philip 411 Jun 17 20:00 id_ed25519-rw-r--r-- 1 philip philip 96 Jun 17 20:00 id_ed25519.pub
Step 4 — Disable Password Authentication (Optional but Recommended)
Once key-based login works, disabling password authentication closes the door
on brute-force attacks completely. An attacker would need your private key file
— guessing passwords becomes irrelevant.
Confirm key login works from a second terminal before doing this.
Open a new terminal window and verify you can log in with your key. Only then
edit sshd_config in your existing session. If you disable password auth and
your key doesn't work, you'll be locked out.
philip@server — disable password authentication
philip@server:~$sudo vi /etc/ssh/sshd_config
Find and set these three lines (search with /PasswordAuth in vi):
# /etc/ssh/sshd_config — find these lines and set them as shownPasswordAuthenticationnoPubkeyAuthenticationyesAuthorizedKeysFile.ssh/authorized_keys
philip@server — reload SSH daemon
# Check config is valid before reloadingphilip@server:~$sudo sshd -t(no output = config is valid)philip@server:~$sudo systemctl reload sshd# Now test from a NEW terminal — password auth should be rejectedphilip@debian:~$ssh -o PreferredAuthentications=password philip@serverphilip@server: Permission denied (publickey).← correct — password auth is now disabled
Managing Multiple Keys
If you connect to many servers — work, home, cloud, Raspberry Pi — you might
want separate key pairs for different purposes. Use -b to name them
at generation time:
philip@debian — multiple named key pairs
# Generate a separate key for work serversphilip@debian:~$ssh-keygen -t ed25519 -C "philip-work" -f ~/.ssh/id_workGenerating public/private ed25519 key pair.Your identification has been saved in /home/philip/.ssh/id_workYour public key has been saved in /home/philip/.ssh/id_work.pub# Generate a key for a Pi projectphilip@debian:~$ssh-keygen -t ed25519 -C "philip-pi" -f ~/.ssh/id_pi# Connect using a specific keyphilip@debian:~$ssh -i ~/.ssh/id_work philip@work-server.example.comphilip@debian:~$ssh -i ~/.ssh/id_pi pi@raspberrypi.local
Chapter 4 (SSH config file) makes managing multiple keys much
cleaner — you can set which key to use per host automatically, so you never
need to remember the -i flag.
Revoking Access — Removing a Key
To stop a machine connecting to a server, remove its public key from
authorized_keys on the server. Each key is one line — delete the
line for the machine you want to revoke:
philip@server — remove a specific key
philip@server:~$vi ~/.ssh/authorized_keysDelete the line containing the key you want to revoke, save and exitNo service restart needed — authorized_keys is read on every connection attempt
Troubleshooting Key Login
If SSH still asks for the server password after copying your key, work through
these checks in order:
philip@debian — debug key authentication
# 1. Check which key SSH is trying to usephilip@debian:~$ssh -v philip@server 2>&1 | grep -E "Offering|Authenticating|refused"debug1: Offering public key: /home/philip/.ssh/id_ed25519 ED25519debug1: Authentications that can continue: publickey,password# 2. Check permissions on the serverphilip@server:~$ls -la ~/.ssh/ .ssh must be 700, authorized_keys must be 600# 3. Check the public key is actually in authorized_keysphilip@server:~$cat ~/.ssh/authorized_keys Should contain a line starting with ssh-ed25519# 4. Check the server's sshd_config allows key authphilip@server:~$grep -E "PubkeyAuth|AuthorizedKeys" /etc/ssh/sshd_configPubkeyAuthentication yesAuthorizedKeysFile .ssh/authorized_keys# 5. Check the auth log on the server for the real errorphilip@server:~$sudo journalctl -u sshd -n 20 Look for lines mentioning your IP — it will say exactly why the key was rejected
Next — Chapter 4: The SSH Config File.
Typing ssh -p 2222 -i ~/.ssh/id_work philip@work-server.example.com
every time is tedious. The ~/.ssh/config file lets you define
aliases, set per-host options, and manage multiple keys automatically —
so ssh work is all you need to type.