What if the single most effective security upgrade on your server takes about ninety seconds and costs nothing? That is not a sales pitch. It is roughly what happens when you replace password logins with a modern Ed25519 key pair and then tighten the SSH daemon around it. Most people never finish the second half. They generate a key, copy it over, and call it done, leaving root password logins and legacy algorithms open for business.
This walkthrough covers the full job: generating the key correctly, loading it into the agent, installing it on the server, hardening `sshd_config`, and verifying that the changes actually took effect. Every step below reflects long-standing OpenSSH behavior rather than a single release, so it holds up regardless of which version your distribution ships. (OpenSSH official project site)
Why Ed25519 beats the old RSA default
For years, `ssh-keygen` defaulted to RSA. That default carried two problems. First, RSA keys are long and slow to verify compared to elliptic-curve options. Second, the older `ssh-rsa` signature scheme relied on SHA-1, which modern OpenSSH releases disabled by default because SHA-1 collisions are practical to produce.
Ed25519 sidesteps both issues. It uses a fixed 256-bit key, produces short signatures, and has no legacy mode to fall back into. The algorithm has shipped in OpenSSH since version 6.5, released in January 2014, so anything you are likely to run today supports it.
There is a practical bonus too: Ed25519 public keys are short enough to paste into a chat window or a cloud console field without wrapping across four lines. Anyone who has wrestled a 4096-bit RSA key into a web form appreciates that.
One caveat worth stating plainly. Ed25519 is not a magic upgrade for an old server running an ancient OpenSSH build. If your host is stuck on a version from before 2014, check `ssh -Q key` on the server to see what key types it actually advertises before you commit.
Generating the key pair correctly
The command itself is short. The details around it are where people go wrong.
- Run `ssh-keygen -t ed25519 -C “you@laptop-2026″` on your local machine. The `-C` flag just appends a comment, which becomes invaluable later when you have six keys and cannot remember which one belongs to which client.
- Accept the default path (`~/.ssh/id_ed25519`) unless you already have a key there. Overwriting an existing key silently breaks every server that trusted it.
- Set a real passphrase when prompted. An empty passphrase works, but it means anyone who copies the private key file owns your servers.
Do not bother with `-b 4096` or similar. Ed25519 keys are fixed at 256 bits, and the size flag is meaningless for this type. If you see a tutorial telling you to set a bit length for Ed25519, that tutorial was copied from an RSA guide.
If you have a hardware security token, `ssh-keygen -t ed25519-sk` creates a resident key on the device. The private key never leaves the hardware, which is the strongest option available for individual workstations. The trade-off is that you need the token plugged in every time you connect.
Loading the key into ssh-agent
Typing a passphrase on every connection gets old fast, and old habits lead to empty passphrases. The ssh-agent solves this properly.
Run `eval “$(ssh-agent -s)”` to start the agent in your shell, then `ssh-add ~/.ssh/id_ed25519` to load the key. On macOS, the agent is usually already running, so `ssh-add –apple-use-keychain` stores the passphrase in the system keychain and survives reboots. On Linux desktops, most modern distributions start an agent automatically at login.
A common mistake: adding the key to the agent on a shared or jump host. The agent socket is a live authentication channel. Anyone who can reach it can use your keys. Keep agent forwarding off unless you have a specific reason, and never enable it to an untrusted host. (EdDSA)
Installing the public key on the server
The public key is the file ending in `.pub`. The private key stays on your machine, always. Copy the public key with `ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server`, which appends it to `~/.ssh/authorized_keys` and fixes permissions along the way.
If `ssh-copy-id` is unavailable, the manual route works fine: create `~/.ssh` with mode `700`, create `authorized_keys` with mode `600`, and paste the single-line public key into it. One key per line, no wrapping.
Here is where permission problems bite. OpenSSH refuses to use a private key that other users can read, and `sshd` will reject key authentication if the home directory or `authorized_keys` is group- or world-writable. This behavior is governed by the `StrictModes` directive, which defaults to yes. The fix is boring but essential:
| Path | Correct mode | Why it matters |
|---|---|---|
| `~/.ssh` | 700 | Blocks other users from listing key files |
| `~/.ssh/id_ed25519` (private) | 600 | Client refuses to load a readable private key |
| `~/.ssh/id_ed25519.pub` | 644 | Public, safe to share |
| `~/.ssh/authorized_keys` | 600 | Server rejects writable auth files |
| Home directory | 755 or stricter | `StrictModes` checks this too |
Hardening sshd_config without locking yourself out
Before editing anything, open a second terminal and keep your current session alive. That single habit prevents most self-inflicted outages. If a change breaks authentication, the live session still works and you can revert.
The core directives to set in `/etc/ssh/sshd_config` are:
- PermitRootLogin no — force administrative access through a named account, then privilege-escalate.
- PasswordAuthentication no — the whole point of key auth. Leaving this on means an attacker can ignore your keys entirely.
- PubkeyAuthentication yes — confirm it is explicitly enabled.
- PermitEmptyPasswords no — blocks accounts with blank passwords.
- KbdInteractiveAuthentication no — closes the PAM-based path that can reintroduce password prompts. Older guides call this `ChallengeResponseAuthentication`, which was deprecated in favor of the new name around OpenSSH 8.7 in 2021.
- MaxAuthTries 3 — limits brute-force attempts per connection.
- AllowUsers or AllowGroups — an allowlist is far stronger than a blocklist.
Validate the file with `sshd -t` before reloading. Then reload with `systemctl reload sshd` (or `ssh` on Debian-family systems). Reload, not restart, keeps existing sessions intact. Test a fresh login in that second terminal before closing the first.
If your workflow involves remote development environments, the same verification discipline applies to editor tooling. The configuration steps in this guide to VS Code extensions and Cursor setup follow a similar pattern of changing config, then confirming the change actually applied. (Pokemon pinball ruby sapphire mgba rumble setup 2026)
Checking what your version actually supports
Two commands answer most questions. `ssh -Q key` lists the key types the local client supports. `sshd -T` dumps the effective server configuration after all includes and defaults are applied, which is the only reliable way to know what `sshd` really thinks.
That second command matters more than people expect. Many distributions ship a drop-in file under `/etc/ssh/sshd_config.d/` that overrides the main config. You edit the main file, reload, and nothing changes because a drop-in set `PasswordAuthentication yes` all over again. `sshd -T` reveals this immediately.
Verifying that key auth is really the only path
After reloading, run `ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no user@server`. A correctly hardened server refuses the connection. If it prompts for a password, something is still open.
Then check the server’s auth log. On most systems, `journalctl -u ssh` or `/var/log/auth.log` shows which method succeeded. You want to see `publickey` and nothing else.
Finally, confirm the key fingerprint matches. `ssh-keygen -lf ~/.ssh/id_ed25519.pub` prints the SHA-256 fingerprint, and `ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub` does the same for the host key. Comparing fingerprints on first connection is the only real defense against a man-in-the-middle on an unfamiliar network.
Common mistakes that quietly undo the work
A few failure patterns show up again and again.
Editing the wrong file. As noted, drop-in configs win. Always confirm with `sshd -T`.
Leaving password auth on “temporarily.” Temporary becomes permanent. Set a calendar reminder and flip it within the same week.
Copying the private key to the server. The private key never travels. If you have already done this, generate a new pair and remove the old public key from every `authorized_keys` file.
Ignoring the home directory mode. A home directory at `775` will cause `sshd` to reject key auth under `StrictModes`, and the error message points at `authorized_keys`, which sends people chasing the wrong file.
Skipping the second terminal. The number of locked-out servers caused by a missing safety session is genuinely large.
Backup and recovery workflows deserve the same care. If you maintain emulator or tooling setups alongside your server work, the same “verify after every change” principle shows up in guides like this RetroArch cheats setup walkthrough, where a single misconfigured path silently breaks everything downstream.
Where OpenSSH is heading
Two long-term trends are worth knowing. First, post-quantum key exchange. OpenSSH 9.0, released in April 2022, enabled a hybrid key exchange by default to hedge against future quantum attacks on recorded traffic. That protects the session, not your Ed25519 identity key, but it signals the direction of travel.
Second, hardware-backed keys are moving from niche to normal. FIDO/U2F support arrived in OpenSSH 8.2 in February 2020, and organizations with compliance requirements increasingly require a physical token for privileged access.
For key management guidance at the institutional level, NIST’s key management publication remains the reference document most auditors cite. It is dense, but the lifecycle sections are readable and directly applicable.
Conclusion
The full hardening job is smaller than it looks. Generate an Ed25519 key with a real passphrase, load it into the agent, install the public half, fix the five permission modes, set the seven `sshd_config` directives, validate with `sshd -t`, reload, and prove the result with a forced password attempt. That sequence takes minutes and closes the door that most automated attacks walk through.
The part people skip is verification. `sshd -T` and a deliberate failed login tell you what is actually true, not what you intended. Do those two checks every time, keep a second terminal open, and the setup holds.
Frequently asked questions
Is Ed25519 actually more secure than RSA?
It is not that the math is unbreakable; it is that Ed25519 has no legacy mode. RSA keys can be used with the old SHA-1-based `ssh-rsa` scheme, which modern OpenSSH disables by default. Ed25519 avoids that entire class of downgrade. It is also faster and produces much shorter keys.
Do I need to specify a key size for Ed25519?

No. Ed25519 keys are fixed at 256 bits. The `-b` flag is meaningless for this key type, and any tutorial telling you to set `-b 4096` on an Ed25519 command was copied from an RSA guide.
What happens if I set an empty passphrase?
The key works, but the private key file becomes the only protection. Anyone who copies `~/.ssh/id_ed25519` gets full access to every server that trusts it. Use a passphrase and let `ssh-agent` handle the typing.
Why does the server still ask for a password after I installed my key?
Three usual suspects: `PasswordAuthentication` is still set to yes, a drop-in file under `sshd_config.d/` is overriding your edit, or the home directory permissions are too open for `StrictModes`. Run `sshd -T` and check the auth log to see which one applies.
Can I lock myself out while hardening sshd_config?
Yes, easily. Keep an existing session open in a second terminal and test a new login before closing it. Validate with `sshd -t` first, reload rather than restart, and you will almost always catch a broken config while you still have access to fix it.
What is the difference between ed25519 and ed25519-sk?
The `-sk` variant creates a key backed by a FIDO/U2F hardware token. The private key material stays on the device and requires a physical touch to use. It is the strongest option for individual workstations, at the cost of needing the token present for every connection.


