●moray: ssh, sftp & terminal

SSH Keys Explained: Ed25519, RSA, and Where They Should Live

What an SSH key pair actually is, why Ed25519 beats RSA for new keys, and why the private half belongs in the Keychain rather than a file in iCloud Drive.

Keys · Bartłomiej Żabicki · updated 2026-07-26 · 10 min read

An SSH key pair is two files that are useless apart. Most of the confusion around SSH keys comes from not being clear about which half does what, so start there and the rest of the decisions — algorithm, passphrase, storage — answer themselves.

The two halves, precisely

  • The private key is a secret you never send anywhere. It stays on the device that generated it. Possession of it is your identity.
  • The public key is derived from the private one and is safe to hand out. You paste it into ~/.ssh/authorized_keys on every server you want to reach.

Authentication does not involve sending either key to the server. The server sends a challenge, your client signs it with the private key, and the server verifies that signature against the public key it already has on file. The secret never crosses the wire — which is why a compromised server cannot steal a key you used to log into it, and why key auth is strictly better than a password that is transmitted (inside the encrypted channel, but transmitted).

~/.ssh/id_ed25519        ← private. Never leaves the device.
~/.ssh/id_ed25519.pub    ← public. Goes in authorized_keys on servers.

If you have ever emailed yourself a file called id_rsa, that was the wrong half.

Which algorithm: Ed25519, every time

Four key types exist in the wild. Only two are worth your attention.

TypeUse it?Why
Ed25519YesModern elliptic-curve signature. Fast, tiny keys, no parameters to get wrong. Supported by OpenSSH 6.5+ (2014).
RSAOnly if forcedStill secure at 3072–4096 bits, but keys are large, signing is slower, and old tooling may pick the deprecated SHA-1 signature scheme.
ECDSANoWorks, but depends on NIST curves many people would rather avoid, and offers nothing Ed25519 does not.
DSANeverFixed at 1024 bits and removed from modern OpenSSH.

The practical rule: generate Ed25519. Keep an RSA key only for a specific server too old to accept anything else, and label it so you remember why it exists.

# the only generation command you normally need
ssh-keygen -t ed25519 -C "iphone-2026"

# if some ancient appliance forces RSA
ssh-keygen -t rsa -b 4096 -C "legacy-nas"

The -C comment is not decoration. It is the label that appears at the end of the line in authorized_keys, and in two years it is the only thing that will tell you which of five keys belongs to a device you no longer own.

Where the private key should live

This is where most setups get sloppy. A private key is a file, and files end up in the wrong places: synced to a cloud drive, checked into a dotfiles repo, copied to a second laptop "temporarily", pasted into a chat.

Ranked from best to worst:

  1. A hardware-backed keystore. On Apple platforms that is the Keychain: encrypted at rest, gated behind Face ID or Touch ID, and not readable by other apps. The key cannot be exported or used without you being present. This is the correct default on a phone or tablet.
  2. A hardware token. A YubiKey or a Secure-Enclave-backed key (ecdsa-sk / ed25519-sk) means the private key physically cannot be copied off the device.
  3. A file with a strong passphrase, loaded into an agent for the session. Fine on a laptop you control.
  4. A file with no passphrase. Acceptable only for automation with a narrowly scoped key whose loss you have already planned for.
  5. Anywhere that syncs to a cloud drive. Now the key's security is your cloud account's security, and its copies are wherever that account has been signed in.

Passphrase, or biometrics?

Both solve the same problem — "someone got the file, can they use it?" — in different ways.

A passphrase encrypts the private key on disk, so a stolen file is inert without it. The cost is typing it, which is why people go to an agent, and then leave the agent unlocked all day.

Biometric gating in a Keychain-backed store makes the key unusable without a live Face ID or Touch ID check, and the key is never handed to the app as raw bytes to begin with. On a phone this is both stronger in practice and dramatically less annoying, which means you will actually leave it on.

Use a passphrase whenever the key exists as a file. Prefer a store where it does not.

Installing the public key on a server

# from a machine that already has access
ssh-copy-id -i ~/.ssh/id_ed25519.pub deploy@web1.example.com

# or by hand, if ssh-copy-id is unavailable
cat ~/.ssh/id_ed25519.pub | ssh deploy@web1.example.com \
  "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"

Permissions matter more than people expect: OpenSSH refuses to use authorized_keys if the file or its directory is group- or world-writable. If key auth silently falls back to a password prompt, check permissions before anything else — or work the full Permission denied (publickey) checklist.

Once keys work, close the door behind you:

# /etc/ssh/sshd_config
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin prohibit-password

Verify you can still log in in a second session before you disconnect the first one. This advice is old because the mistake is common.

One key per device, not per server

There are two defensible strategies and one bad one.

  • One key per device (recommended): the phone has its own key, the laptop has its own, the CI runner has its own. Losing a device means removing one line per server. You always know which device authenticated.
  • One key per server or role: more isolation, more bookkeeping. Worth it for high-consequence systems.
  • One key everywhere, copied between devices: every copy is a new place to lose it, and the audit trail is useless because every device is the same identity.

While you are here: put an expiry note in your calendar. Keys do not expire on their own, which means authorized_keys files quietly accumulate access for laptops that were recycled years ago.

# audit what actually has access
awk '{print $3, $1}' ~/.ssh/authorized_keys

Fingerprints: your key vs the server's key

Two different fingerprints get confused constantly.

  • Your key's fingerprint identifies you to the server. ssh-keygen -lf id_ed25519.pub prints it, and GitHub or your hosting panel shows the same string next to the uploaded key.
  • The host key's fingerprint identifies the server to you. It is what the trust-on-first-use prompt shows, and it is stored in known_hosts afterwards.

They serve mirror-image purposes. When a client warns that "the host key has changed", your key is not the problem — the machine you are talking to is claiming a new identity, either because it was rebuilt or because it is not the machine you think it is.

# your key's fingerprint
ssh-keygen -lf ~/.ssh/id_ed25519.pub

# a server's host key fingerprint, from the server itself
ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub

Compare out of band the first time. After that, let the client shout at you if it changes — that warning is the whole point, and what to do when it fires is a guide of its own.

The short version

  • Generate Ed25519. Give it a -C comment naming the device.
  • Keep the private half in a Keychain or hardware token; use a passphrase whenever it is a file.
  • One key per device, so revocation is one line per server.
  • Install with ssh-copy-id, fix directory permissions, then turn off password auth — after testing in a second session.
  • Audit authorized_keys occasionally and delete what you no longer recognise.

Next: SSH port forwarding explained, or jump hosts and ProxyJump if your servers hide behind a bastion.

Written by Bartłomiej Żabicki

iOS developer writing Swift since 2015, with a homelab he administers from an iPhone more often than he would like to admit. Moray is the SSH client he wanted to exist.

Frequently asked

Ed25519 or RSA — which should I use?
Ed25519 for anything new. It is faster, the keys are tiny, and it avoids the parameter choices RSA forces on you. Keep RSA only for servers too old to accept Ed25519, and if you must, use at least 4096 bits.
Should my SSH key have a passphrase?
Yes, if the private key can ever be read as a file. On a device where the key lives in the Keychain behind Face ID or Touch ID, biometric gating gives you the same protection with far less friction — the key cannot be exported or used without you being present.
Can I reuse one key for every server?
You can, and many people do, but a compromise then affects everything. A reasonable middle ground is one key per device — so revoking a lost phone means removing one line from authorized_keys on each server, and nothing else changes.

try it yourself

Moray does all of this natively

A real terminal, dual-pane SFTP, tunnels and jump hosts on iPhone, iPad and Mac. Keys stay in the Keychain, hosts sync over your own iCloud, and there is no account to make.