The right way to generate an SSH key on Linux in 2026 is ssh-keygen -t ed25519 -C "you@host", set a passphrase, and load the key into ssh-agent. Ed25519 is the modern default — small key, fast signature, no known attacks. The team that has this set up has passwordless SSH from any terminal session without typing the passphrase every time.
Table of contents
- Why ed25519 and not RSA
- The ssh-keygen command
- The ssh-agent: do not retype the passphrase
- The right SSH config
- Pushing the public key to a server
- Common mistakes
- FAQ
Why ed25519 and not RSA
Ed25519 is a signature algorithm based on Curve25519. The signatures are 64 bytes, the public key is 32 bytes, and the algorithm is fast on every architecture. The security level is comparable to a 3000-bit RSA key. The right answer for new keys in 2026 is Ed25519.
RSA keys are still valid and still work everywhere. The wrong answer is to keep generating 4096-bit RSA keys in 2026 because a tutorial from 2010 said so. The right answer is to use Ed25519 unless a specific system you need to SSH to does not support it. Almost every SSH server in production today supports Ed25519. The exception is some very old network gear (Cisco IOS versions from before 2015, some embedded systems) that only accepts RSA.
The right answer for a new project is Ed25519. The right answer for an existing fleet with RSA keys is to leave them alone until they need to be rotated. The wrong answer is to convert an RSA key to Ed25519 — the right answer is to generate a new Ed25519 key, deploy the new public key, and remove the old RSA key.
The ssh-keygen command
The right invocation:
ssh-keygen -t ed25519 -C "alice@laptop"
The -t flag is the key type. The -C flag is a comment, which goes into the public key file and shows up in authorized_keys on the server. The right answer for the comment is your email or a description of the workstation. The right answer is to not leave the comment blank — a comment-less key is hard to identify when you see it in 50 different authorized_keys files.
The command will prompt for a file location and a passphrase. The right answer for the file location is the default, which is ~/.ssh/id_ed25519. The right answer for the passphrase is to set one. A key without a passphrase is a security liability — anyone with the file can use the key. A key with a passphrase is useless to an attacker who steals the file.
The output:
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/alice/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/alice/.ssh/id_ed25519
Your public key has been saved in /home/alice/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:abc123... alice@laptop
The key's randomart image is:
+--[ED25519 256]--+
| .o+=*+B |
| o.oo=+o= |
| o .. o.o+. |
| o . o . |
| S . o |
| o o . |
| o. .. |
| . o+.. |
| oE*+. |
+----[SHA256]-----+
The randomart image is a visual fingerprint of the key. The right answer is to look at it and remember what it looks like — if you SSH to a box and the randomart for the host key is different, something is wrong (likely a man-in-the-middle attack).
The ssh-agent: do not retype the passphrase
The right way to avoid retyping the passphrase on every SSH connection is to load the key into ssh-agent. The agent runs in the background and provides the key to the SSH client on demand.
The right way to start the agent depends on the shell. For Bash:
eval "$(ssh-agent -s)"
For Zsh:
eval "$(ssh-agent -z)"
For Fish:
ssh-agent -c
The agent outputs the environment variables (SSH_AUTH_SOCK and SSH_AGENT_PID) that the SSH client needs. The eval runs the output as a command, setting those variables in the current shell. The right answer is to put this in ~/.bashrc (or the equivalent for your shell) so the agent starts on every login.
The right way to add the key to the agent:
ssh-add ~/.ssh/id_ed25519
You will be prompted for the passphrase once. After that, every SSH connection that uses this key succeeds without a prompt. The right answer is to use the agent. The wrong answer is to disable the passphrase or to write it in a script.
The right SSH config
The right way to set up the SSH client is ~/.ssh/config. The file is read on every connection, and the right answer is to put defaults in it. Example:
Host *
AddKeysToAgent yes
IdentitiesOnly yes
ServerAliveInterval 60
ServerAliveCountMax 3
Host *.example.com
User alice
IdentityFile ~/.ssh/id_ed25519
The AddKeysToAgent yes line is the key trick — it tells the SSH client to add any key it uses to the agent automatically, so you do not have to run ssh-add explicitly. The IdentitiesOnly yes line tells the client to use only the specified key, not to try every key in the agent. The wrong answer is to omit these — the right answer is to use them.
The right answer for the file mode is chmod 600 ~/.ssh/config. The wrong answer is to leave the file world-readable, which causes ssh to refuse to read it.
Pushing the public key to a server
The right way to deploy the public key to a server is ssh-copy-id:
ssh-copy-id [email protected]
This prompts for the server password one last time, then appends the public key to ~/.ssh/authorized_keys on the server. The right answer is to use this command, not to manually copy the file. The wrong answer is to copy the private key — the public key is the only one that should ever leave the workstation.
The right answer if ssh-copy-id is not available is to do it manually:
cat ~/.ssh/id_ed25519.pub | ssh [email protected] "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
The mode is important. The wrong answer is to leave ~/.ssh or ~/.ssh/authorized_keys world-readable, which causes sshd to reject the key with a confusing permission error.
Common mistakes
The most common mistake is to share the private key across machines. The right answer is one key per device. A workstation has its own key, a server has its own key, a CI runner has its own key. The private key never leaves the device that generated it.
The second most common mistake is to commit the private key to a Git repository. The right answer is to make sure .ssh/ is in .gitignore and to never copy a key to a place that gets committed. The right answer if a key does get committed is to assume the key is compromised, generate a new one, remove the old public key from every server, and rotate.
The third most common mistake is to use the same key for too long. The right answer for key rotation is annual for low-value keys, quarterly for high-value keys, and immediately if the device is lost or stolen. The rotation procedure is the same as the initial deploy: generate a new key, push the new public key to the server, and remove the old public key.
FAQ
Is ed25519 supported by every server?
Yes, by every OpenSSH server version 6.5 and later (2014). For older servers, the right answer is to fall back to RSA. The right answer for verifying is to check the server’s OpenSSH version with ssh -V on the client and sshd -T | grep version on the server.
Can I have multiple keys for different purposes?
Yes. Generate one key per purpose (one for GitHub, one for personal servers, one for work). The right answer is to name them clearly: ~/.ssh/id_ed25519_github, ~/.ssh/id_ed25519_personal, ~/.ssh/id_ed25519_work. The right answer in ~/.ssh/config is to use the IdentityFile directive per host so the right key is used automatically.
What is the difference between ssh-agent and gpg-agent?
ssh-agent is the SSH-specific agent. gpg-agent is the GPG agent, which can also act as an SSH agent with enable-ssh-support. The right answer for most users is ssh-agent — it is simpler and has no GPG dependencies. The right answer for users who already use GPG is gpg-agent because it integrates with the same key-management workflow.
My key passphrase is wrong but ssh-agent does not prompt. Why?
The most common cause is that the key was not added to the agent — the agent is providing a different key (or no key), and the server is rejecting the connection. The right answer is to run ssh-add -l to see which keys are loaded, and ssh-add -D to clear them, then re-add the correct key. The right answer for verifying a key is to run ssh-keygen -y -f ~/.ssh/id_ed25519 — this prompts for the passphrase and prints the public key. If the passphrase is wrong, this fails.
Can I use a hardware key (YubiKey) for SSH?
Yes. The right answer is to generate the key on the YubiKey with ssh-keygen -t ed25519-sk. The -sk suffix is for security keys. The private key never leaves the YubiKey, which is the right answer for high-value use cases. The wrong answer is to copy a regular SSH key to a hardware device — that is the same security posture as a software key, just with extra steps.
What is the difference between authorized_keys and known_hosts?
authorized_keys is on the server and lists the public keys that are allowed to log in. known_hosts is on the client and lists the server host keys that the client has verified. The two work together: the client checks the server’s host key against known_hosts (or SSHFP), and the server checks the client’s public key against authorized_keys.
Is ssh-add -K (capital K) different on macOS?
Yes. The -K flag on macOS tells the agent to store the passphrase in the macOS Keychain so it persists across reboots. The right answer on macOS is ssh-add --apple-use-keychain (the modern equivalent) and to configure ~/.ssh/config with UseKeychain yes for each host. On Linux, the right answer is the keychain package or a custom systemd user service to persist the agent across reboots.
How do I disable password authentication on the server?
Edit /etc/ssh/sshd_config and set PasswordAuthentication no. Then sudo systemctl reload sshd. The right answer is to do this only after key-based auth is working — if you break the key-based config, the wrong answer is to lock yourself out of the server.
If you are sizing the infrastructure for the kind of project this post covers, the RunxBuild hosting calculator is the right place to model the line items. The compute, the memory, the storage, the bandwidth, the database - each one is a separate number, and the team’s mental model for the platform is the sum of those numbers. The RunxBuild dashboard is where the team sees the actual usage in one place.
Useful related references: