For a new workstation key, generate Ed25519. It is compact, fast, and broadly supported by modern OpenSSH. Generate RSA 4096 only when a server, appliance, or old policy cannot accept Ed25519. ECDSA works, but it is rarely the clearest default when Ed25519 is available.
The choice in one table
| Algorithm | Use it when | Avoid it when |
|---|---|---|
| Ed25519 | You control current OpenSSH clients and servers | A legacy endpoint rejects it |
| RSA 4096 | You need compatibility with older SSH stacks | You are choosing it only because it is familiar |
| ECDSA | A required environment explicitly standardises on it | You have no interoperability reason |
The algorithm label is only one layer. A private key copied into chat, committed to a dotfiles repo, or left without a passphrase is still a compromised key.
Generate a key you can identify later
ssh-keygen -t ed25519 -a 100 -C "laptop-2026-work"
-a 100 raises the bcrypt KDF rounds used to protect the private key passphrase. The comment is not security metadata; it is an operational label that helps you remove the right key six months later.
Do not share the private file ending in no extension (for example
id_ed25519). The.pubfile is the one intended for servers, Git hosts, andauthorized_keys.
Verify what you are actually installing
Before pasting a public key into a provider dashboard, inspect its fingerprint:
ssh-keygen -lf ~/.ssh/id_ed25519.pub
On a server, keep permissions strict enough that OpenSSH will trust them:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
Then test with verbosity before declaring authentication broken:
ssh -vvv git@example.com
The useful lines say which identities the client offered and which one the server accepted. That beats repeatedly pressing Enter through a key-selection prompt and hoping the agent picks the right key.
Stop the agent from guessing: name the host
A generated key is only half the setup. Put the connection policy in ~/.ssh/config so ssh prod-api says what you mean instead of relying on whichever identity your agent happens to offer first:
Host prod-api
HostName api.example.com
User deploy
IdentityFile ~/.ssh/id_ed25519_work
IdentitiesOnly yes
ServerAliveInterval 30
IdentitiesOnly yes is the line that matters on a machine with several loaded keys — without it, the client sprays every agent identity at the server and you get a confusing "Too many authentication failures" instead of a clean rejection.
| Situation | Config choice | Why |
|---|---|---|
| Work vs. personal Git host | Separate Host alias per identity | Keeps unrelated identities from ever being offered to the wrong host |
| Bastion host | ProxyJump bastion | Avoids a hand-written tunnel chain in every terminal tab |
| Temporary debug server | Its own Host alias | Makes the config diff — and later removal — obvious |
| Production | StrictHostKeyChecking yes | Refuses a changed host key instead of training the team to type "yes" through a warning |
Never resolve an unknown-host-key warning with
StrictHostKeyChecking noin shared or production config. Verify the server fingerprint through a separate channel — the SSH config builder generates the alias block above without a typo, but it can't verify the fingerprint for you.
Key hygiene that actually survives a team
Use one key per person and device, retain the public-key comment, and remove keys during offboarding. For high-value production access, consider short-lived SSH certificates rather than an ever-growing authorized_keys file. The win is revocation: deleting a single signer or certificate authority policy is more tractable than finding a copied public key across 80 hosts.
Ed25519 is the sensible default. The rest of the work is knowing where each key is authorised and being able to revoke it quickly.
