Ops Journal · Practical notes on running software in production

SSH host keys: what that SHA256 fingerprint actually identifies

Published 2026-10-07 · 7 min read

The first time you connect to a host, SSH shows a fingerprint and asks whether to trust it. Most people type yes. That prompt is the only point in the connection where the identity of the server is established, so it is worth understanding what is being compared and what it protects against.

The fingerprint identifies a key, not a host

A server has one or more host keys, one per algorithm, generated when SSH was first set up. The fingerprint is a hash of the public half of one of those keys. It says nothing about the hostname, the IP, or the machine's identity in any other sense — it identifies a specific key pair.

List the host keys on a machine you have access to:

ls -l /etc/ssh/ssh_host_*_key.pub

A typical result is three or four files, one for each algorithm the server offers: ed25519, rsa, ecdsa, and possibly dsa. Modern OpenSSH generates ed25519 and rsa by default.

Reading a fingerprint

ssh-keygen -lf prints the fingerprint of a public key file:

ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub
256 SHA256:+7+QJiOKPZDSunXEnfE89SIVSSUsLT2OFPRu520xGAE root@fakher-prd2e (ED25519)

Four fields, each meaningful:

  • 256 — the key size in bits
  • SHA256:+7+QJ... — the fingerprint, base64-encoded SHA256 of the key
  • root@fakher-prd2e — the comment, usually user@host from generation time
  • (ED25519) — the algorithm

The comment is not part of the key and not part of the fingerprint. It is free text, and on a host key it frequently records whoever generated it. Do not treat it as authoritative — a copied key can carry any comment.

Older documentation shows fingerprints as colon-separated hex (c3:1a:...). That is the MD5 format, and OpenSSH no longer prints it by default because MD5 collisions are practical. If you need to compare against an old record, ask for it explicitly:

ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub -E md5

Prefer comparing SHA256 fingerprints. Converting an MD5 record to SHA256 is not possible — they are different hashes of the same key, so the old record has to be regenerated.

Getting the fingerprint of a remote host without connecting

The useful trick is querying a host's keys before you have ever connected, so you can compare against a value obtained through another channel:

ssh-keyscan -t ed25519 host.example.com 2>/dev/null | ssh-keygen -lf -

ssh-keyscan retrieves the public keys the server offers, and piping into ssh-keygen -lf - prints their fingerprints. This is the command to run when you want to verify a host before adding it to known_hosts.

It comes with a caveat worth stating plainly: ssh-keyscan is itself an unauthenticated request. If the network is already compromised, the keys it returns are the attacker's, and comparing them proves nothing. Verification only has value when the expected value comes from a different channel — a printed record, a configuration management system, a colleague reading it off the console.

Where the trust decision is stored

When you accept a host key, it is written to known_hosts:

grep host.example.com ~/.ssh/known_hosts

A line contains the hostname (or hashed hostname), the algorithm, and the base64 public key. With HashKnownHosts yes, the hostname is hashed, which is why grep for a hostname may find nothing even though the entry exists. To look it up in that case, ask SSH to do it:

ssh-keygen -F host.example.com

-F finds a host in known_hosts regardless of whether the names are hashed. ssh-keygen -R host.example.com removes the entry, which is the correct action after a legitimate server rebuild.

The warning that means what it says

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

This appears when the key presented does not match the one recorded. It has two possible causes and they need different responses:

  • The host was rebuilt or rekeyed. Legitimate. The fix is ssh-keygen -R host followed by reconnecting and accepting the new key.
  • Something is intercepting the connection. The host key changed because you are talking to a different machine. Removing the entry and reconnecting is exactly the wrong response.

The way to tell them apart is to obtain the current fingerprint out of band — the cloud console, the hypervisor, a colleague on the host — and compare. When that is not possible, treat the change as hostile until proven otherwise, because the costs are asymmetric: an unnecessary five minutes of checking against a successfully intercepted session.

Verifying a fingerprint you were given

When someone hands you a fingerprint to compare, match the whole string. A common mistake is checking only the first few characters, which is not what the prompt asks and not a meaningful check — the security of the comparison comes from the full hash.

# the value to compare is the whole SHA256:... field, not a prefix
ssh-keyscan -t ed25519 host.example.com 2>/dev/null | ssh-keygen -lf -

Managing this across many hosts

For anything beyond a handful of machines, verifying fingerprints by hand does not scale and will not happen. The two approaches that do:

  • Provision the keys. Bake the expected host keys into the image or configuration management, so the client trusts them from first boot with no prompt and no human decision in the loop.
  • Certificates. Use an SSH certificate authority. The client trusts the CA once, and the CA signs host keys with a validity period. Host identity is then verified against a signature rather than a stored fingerprint, and rotation stops requiring a change on every client.

For a single server the manual check is fine. For a fleet, one of the two above is the difference between a policy that exists and a policy that is followed.