SSH key best practices: Ed25519, agents, rotation
Which SSH key type to use in 2026, how to protect it with a passphrase and an agent, when to rotate, and how to find the weak keys you forgot you had.
On this page
Use Ed25519What about RSA, ECDSA and DSA?Always set a passphrase, and let an agent hold itOne key per deviceDo not forward your agentConsider a hardware keyTighten authorized_keysRotate, and removeAudit what you haveAt fleet scale, use certificatesThe Keychain view in Gatesys SSHFAQAn SSH key is a credential that never expires by itself, is rarely looked at twice, and often opens production. Most teams treat it with less care than a password. This is a short, practical set of rules for 2026: which key to create, how to hold it, and how to find and retire the ones that should have gone years ago.
Use Ed25519
ssh-keygen -t ed25519 -a 100 -C "alice@laptop-2026"-t ed25519picks the algorithm. Keys are small, signing is fast, and there are no parameters to get wrong.-a 100raises the number of key-derivation rounds, which slows down anyone guessing the passphrase of a stolen key file.-Cis a comment. Put the owner and the device in it. In two years it will be the only clue to what a line inauthorized_keysis for.
Ed25519 has been in OpenSSH since 6.5, released in 2014, so anything still in support accepts it.
What about RSA, ECDSA and DSA?
| Type | Verdict |
|---|---|
| Ed25519 | The default choice |
| RSA, 3072 bits or more | Fine where Ed25519 is not accepted. ssh-keygen -t rsa -b 4096 |
| RSA, 2048 bits | Not broken, but below the 3072 bits OpenSSH has generated by default since 8.0. Replace it at your next rotation |
| RSA, 1024 bits | Replace now |
| ECDSA | Works. There is no reason to prefer it to Ed25519 |
| DSA | Gone. OpenSSH switched it off by default in 9.8 and removed it in 10.0 |
A separate matter is the signature algorithm. Since OpenSSH 8.8, RSA keys sign with SHA-2, and the old SHA-1 ssh-rsa signature is off by default. An RSA key still works, but a very old server may not understand the new signature. That shows up as no mutual signature algorithm; see Permission denied (publickey).
Always set a passphrase, and let an agent hold it
A key file without a passphrase is a password in a text file. With one, a copied file is useless without it.
The agent means you type the passphrase once a session, not once a connection:
Host *
AddKeysToAgent yes
# macOS: keep the passphrase in the login keychain
IgnoreUnknown UseKeychain
UseKeychain yesTo limit how long a key stays loaded:
ssh-add -t 8h ~/.ssh/id_ed25519One key per device
Do not copy one private key to your laptop, your desktop and a build server. Give each device its own key and authorise each on the servers it needs. When a laptop is lost, you remove one line from authorized_keys, and nothing else stops working.
For the same reason, a private key has no place on a bastion. Reach hosts behind it with ProxyJump, which authenticates every hop from your own machine.
Do not forward your agent
ssh -A makes your agent usable from the remote host, by you and by anyone with root there, for as long as you are connected. ProxyJump covers nearly every case agent forwarding was used for and exposes nothing. If you truly need to forward, do it for one host, and load the key with ssh-add -c so each use asks you to confirm.
Consider a hardware key
OpenSSH 8.2 added keys backed by a FIDO2 security key:
ssh-keygen -t ed25519-sk -O verify-required -C "alice@yubikey"The file on disk is only a handle. The secret stays in the hardware, and a login needs a touch, plus a PIN with verify-required (OpenSSH 8.4 or later). A stolen laptop gives away nothing usable.
Tighten authorized_keys
Each line in authorized_keys can carry options in front of the key. For a key that exists to run one job:
restrict,from="10.0.3.0/24",command="/usr/local/bin/backup" ssh-ed25519 AAAAC3... backup@cirestrictturns off port forwarding, agent forwarding, X11 and the terminal in one word.from=accepts the key only from those addresses.command=runs that command whatever the client asks for.
Rotate, and remove
Rotation matters less for the mathematics than for the housekeeping. A key that is three years old has been on machines you no longer own and in backups you forgot.
- Create the new key.
- Add its public half to each server:
ssh-copy-id -i ~/.ssh/id_ed25519_2026.pub deploy@server. - Test with the new key only:
ssh -i ~/.ssh/id_ed25519_2026 -o IdentitiesOnly=yes deploy@server. - Remove the old line from
authorized_keyson each server. - Delete the old private key and take it out of the agent with
ssh-add -d.
Step 4 is the one that gets skipped. A rotation that leaves the old key authorised has added a key and retired none.
Audit what you have
On your own computer:
for f in ~/.ssh/*.pub; do ssh-keygen -lf "$f"; done
ssh-add -lEach line begins with the key’s size and ends with its type, such as 256 SHA256:... alice@laptop (ED25519) or 2048 SHA256:... (RSA). Anything that says DSA, or RSA with fewer than 3072 bits, goes on the list to replace.
On a server, the same command on authorized_keys shows who can get in:
ssh-keygen -lf ~/.ssh/authorized_keysA fingerprint nobody can put a name to is a finding.
At fleet scale, use certificates
Past a few dozen servers and people, managing authorized_keys files stops scaling. SSH certificates turn it around: servers trust one certificate authority, set with TrustedUserCAKeys, and people are issued short-lived certificates for their keys with ssh-keygen -s. Access that expires by itself removes most of the need to rotate.
The Keychain view in Gatesys SSH
Gatesys SSH does the audit for you. Its Keychain, part of the free plan, lists every key in ~/.ssh and whatever your agent holds, each with its type, its fingerprint and the saved hosts that use it. Each key carries a status:
| Status | Meaning |
|---|---|
| Insecure | A DSA key, or an RSA key shorter than 3072 bits |
| Rotate | Older than three years |
| In agent | Loaded in the running agent |
| On disk | A key file that is not loaded |
The Used by column answers the question that makes rotation slow: which hosts will I have to touch if I replace this key? The app reads keys from the agent the way OpenSSH does, including 1Password, gpg-agent, Pageant and the Windows OpenSSH agent, and it never copies a private key anywhere. See Authentication.
FAQ
Is Ed25519 better than RSA?
For new keys, yes. Ed25519 keys are shorter, faster to use and have no size parameter to choose badly. RSA at 3072 bits or more is still secure, and is the fallback for old systems that do not support Ed25519.
Should an SSH key have a passphrase?
Yes, for any key a person uses. The agent removes the inconvenience. Keys for unattended jobs are the exception. Limit those with restrict, from= and command= in authorized_keys.
How often should I rotate SSH keys?
There is no single standard. Every one to three years is a common rule, and immediately when a device is lost, a person leaves, or a key may have been copied. Certificates with short lifetimes make the question go away.
Is a 2048-bit RSA key still safe?
It is not broken. It is below the size OpenSSH now generates by default, so plan to replace it at your next rotation, not in a panic.
Where should I store my private key?
In ~/.ssh on the device that uses it, with mode 600 and a passphrase, or on a hardware security key. Not in cloud storage, not in a repository, and not on a bastion.
