SSH Keys Explained: How They Work, ssh-keygen, Ed25519 and Safe Habits
SSH keys let you log in to servers and push to Git without typing a password, and they are far harder to steal or guess. We generated throwaway keys to show what each file contains, what is safe to share and what must never leave your machine.
- An SSH key pair has a public key you can share and a private key you never share.
- Create one with
ssh-keygen -t ed25519 -C "you@example.com". Ed25519 is the modern default. - Protect the private key with a passphrase and use
ssh-agentso you only type it once. - Use separate keys per purpose, remove old keys from servers, and never paste a private key anywhere.
Passwords for servers get reused, guessed, phished and shared in chat messages. SSH keys replace them with a pair of mathematically linked files: one you can hand to anyone, and one that stays on your machine. Even if a server is compromised, attackers only learn your public key, which is useless to them.
We generated throwaway keys with OpenSSH 10.6 in Git Bash on Windows and inspected them. The outputs below come from that run; the keys were deleted afterwards. We did not log in to a real server for this article, so the server-side commands are standard examples.
What are SSH keys?
SSH, short for Secure Shell, is the protocol used to log in to remote machines and to talk to Git hosts such as GitHub and GitLab. SSH keys use public-key cryptography: a private key, kept secret, and a public key, derived from it and safe to share. Anything signed by the private key can be verified with the public key, but the private key cannot be worked out from the public one.
How key login works
- You put your public key in the server’s list of allowed keys,
~/.ssh/authorized_keys. - When you connect, the server sends a challenge.
- Your SSH client signs the challenge with your private key.
- The server checks the signature with the public key it already has. If it matches, you are in.
Your private key never travels over the network. That is the core security advantage over passwords, which must be sent to the server every time.
Generating a key
ssh-keygen -t ed25519 -C "demo@example.com"
-t ed25519 chooses the key type; -C adds a comment, usually an email, to help you recognise the key later. Without -C, the comment defaults to your user and computer name, which you may not want to share with every server and service. ssh-keygen asks where to save the key, defaulting to ~/.ssh/id_ed25519, and for a passphrase. For our test we skipped the passphrase so the script could run unattended; do not do that for keys you actually use.
The two files
id_ed25519 411 bytes private key
id_ed25519.pub 98 bytes public key
$ head -1 id_ed25519
-----BEGIN OPENSSH PRIVATE KEY-----
$ cat id_ed25519.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII+IjKako5WgqS1oQgx3QhLQ... demo@example.com
The .pub file is one line: the key type, the key itself in Base64, and the comment. That is the part you copy to servers and websites. The file without an extension is the private key. Treat it like the master password to every machine that trusts it.
You can always regenerate the public key from the private key with ssh-keygen -y -f id_ed25519; our test produced the same ssh-ed25519 AAAA... line. The reverse is impossible.
Ed25519 vs RSA
| Ed25519 | RSA 4096 | |
|---|---|---|
| Public key size in our test | 98 bytes | 735 bytes |
| Security | Strong, modern | Strong at 3072+ bits |
| Speed | Very fast | Slower |
| Compatibility | OpenSSH 6.5+ (2014) and most modern services | Almost everything, including very old systems |
| Command | ssh-keygen -t ed25519 |
ssh-keygen -t rsa -b 4096 |
Use Ed25519 unless a system cannot accept it. Avoid DSA keys, which modern OpenSSH no longer supports, and RSA keys shorter than 2048 bits. Hardware-backed types such as ed25519-sk keep the private key on a security key like a YubiKey, so it can never be copied off your computer at all.
Fingerprints
$ ssh-keygen -lf id_ed25519.pub
256 SHA256:s+pZpCcc6uy+S6F9hcuw6RQxIWVyVo+iwLMoLrj3N0U demo@example.com (ED25519)
A fingerprint is a short hash of a public key, used to identify it. Services like GitHub show fingerprints in their key settings, so you can match each listed key to a file on your machine. The first time you connect to a new server, SSH shows the server’s fingerprint and asks you to confirm it. Check it against a trusted source rather than typing “yes” by habit, because that prompt is your protection against connecting to an impostor.
Passphrases
A passphrase encrypts the private key file on disk. If your laptop is stolen or a backup leaks, the key is useless without it. We encrypted a test key and tried the wrong passphrase:
$ ssh-keygen -y -P wrong -f locked
Load key "locked": incorrect passphrase supplied to decrypt private key
Use a long, memorable passphrase, not a short password. To change it later without making a new key, run ssh-keygen -p -f ~/.ssh/id_ed25519.
Tip: Never pass a passphrase on the command line in a real setup, as we did with -P for this test. It can end up in your shell history and be visible to other processes. Let ssh-keygen prompt you instead.
ssh-agent: type the passphrase once
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
The agent holds the decrypted key in memory for your session, so every git push and ssh uses it without asking again. macOS Keychain, Windows’ OpenSSH Authentication Agent service and most Linux desktops can start the agent automatically. Be careful with agent forwarding (ssh -A): it lets the remote machine use your agent while you are connected, so only forward to servers you fully trust.
Adding a key to a server
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server.example.com
This appends your public key to ~/.ssh/authorized_keys on the server. Without ssh-copy-id, you can paste the public key line into that file yourself. Permissions matter: OpenSSH may refuse keys if the folder or file is writable by others. Typical settings are chmod 700 ~/.ssh and chmod 600 ~/.ssh/authorized_keys on the server, and 600 for your private key. Once key login works, many teams disable password login on the server entirely.
Keys for GitHub and CI
Add your public key in your Git host’s account settings, then test with ssh -T git@github.com. Use SSH remote URLs such as git@github.com:org/repo.git. Our Git tutorial covers setting up remotes.
For automation, do not reuse your personal key. Create a dedicated key with limited access, such as a read-only deploy key for one repository, and store the private key in your CI system’s secret store, never in the repository or a Docker image. Our environment variables guide and GitHub Actions guide explain how secrets are injected safely.
The SSH config file
# ~/.ssh/config (example, not run for this article)
Host staging
HostName 203.0.113.10
User deploy
IdentityFile ~/.ssh/id_ed25519_staging
IdentitiesOnly yes
Host github.com
IdentityFile ~/.ssh/id_ed25519_github
Now ssh staging connects with the right user and key. IdentitiesOnly yes stops SSH trying every key in your agent, which can trigger “too many authentication failures” errors on servers that limit attempts.
Key hygiene
- Never share or paste a private key, including into chat, tickets, AI tools or code.
- One key per purpose or device, so a lost laptop means revoking one key, not all access.
- Review
authorized_keysand your Git host’s key list regularly; remove keys for people and machines that no longer need access. - Rotate keys when someone leaves or a device is lost, and consider SSH certificates or short-lived credentials for larger teams.
- Back up carefully: an encrypted key in a password manager is fine; a plain key in a shared folder is not.
- Scan repositories for accidentally committed keys; secret scanners in CI catch these quickly.
Troubleshooting “Permission denied (publickey)”
This is the most common SSH error. Work through it in order:
- Run with verbose output:
ssh -v user@servershows which keys the client offers and where it stops. - Is the right key loaded?
ssh-add -llists keys in the agent. Add the missing one, or setIdentityFilein your config. - Is the public key on the server? Check
~/.ssh/authorized_keysfor the correct user, compare fingerprints, and make sure the key is on a single line. - Are permissions too open? The home directory,
.sshfolder andauthorized_keysmust not be writable by other users. - Right user and host? A typo in the username or an old IP address produces the same error.
On the server side, the SSH service’s logs usually explain exactly why a key was refused. These commands are standard examples and were not run against a server for this article.
Final thoughts
SSH keys are simple once you know the rule: the public key goes everywhere, the private key goes nowhere. Generate an Ed25519 key with a strong passphrase, load it into ssh-agent, use separate keys for automation, verify server fingerprints, and clean up old keys. Those habits make remote access both easier and far more secure than passwords.
Frequently asked questions
What is the difference between a public and private SSH key?
The public key can be shared and is placed on servers and services. The private key stays secret on your device and proves your identity by signing challenges.
Should I use Ed25519 or RSA?
Use Ed25519 for new keys: it is modern, fast and compact. Use RSA with at least 3072 bits only for systems that do not support Ed25519.
Do I need a passphrase on my SSH key?
Yes, for personal keys. It encrypts the private key file, so a stolen copy is useless. ssh-agent means you only type it once per session.
Where are SSH keys stored?
By default in the .ssh folder of your home directory, such as ~/.ssh/id_ed25519 for the private key and ~/.ssh/id_ed25519.pub for the public key.
What should I do if my private key is exposed?
Remove the matching public key from every server and service immediately, generate a new key pair, and check access logs for unexpected use.
Keep learning
Need help with testing, WordPress or SEO?
We help teams ship better software and grow their sites. Tell us what you are working on and we will suggest a clear next step.