Provisioning a fleet of new servers means ssh-keyscan is the fast way to pull host keys without ever logging in. The examples use ssh-keyscan from the Ubuntu openssh-client package, version 9.6p1-3ubuntu13.19 on this machine. Allow about 15 minutes. You need a shell, network access to the target SSH service, and permission to write the destination file.
Security boundary: a scan proves what a server presented at scan time, nothing more. It does not prove that key belongs to the server you think it does. Treat unverified output as trust data and a person in the middle can substitute their own key. Get a trusted fingerprint from the server owner, console, deployment record or another independent channel before you accept a new key.
Start with a single host and a short timeout. Replace server.example.org with a hostname or address you are authorised to query:
$ ssh-keyscan -T 5 -t ed25519 server.example.org
A successful result is a line containing the host name, a key type and a base64-encoded public key, similar to this:
server.example.org ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI...
The default scan requests every supported RSA, ECDSA, Ed25519 and security-key type. Pinning -t ed25519 makes the first check easier to read and skips collecting types your policy does not use. None of this needs login credentials or an encrypted SSH session.
Checkpoint: a returned line is evidence an SSH service answered, not evidence its identity is correct. A host that is down or has no SSH service produces no key line at all, and can take until the timeout to be declared unavailable.
Before scanning a remote fleet, test the syntax against a service whose key you can check independently. This machine has an SSH service on loopback:
$ ssh-keyscan -T 2 -t ed25519 127.0.0.1
# 127.0.0.1:22 SSH-2.0-OpenSSH_9.6p1 Ubuntu-3ubuntu13.19
127.0.0.1 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI...
$ printf 'exit status: %s\n' "$?"
exit status: 0
The banner is diagnostic output from the SSH service; the key line is the actual known-hosts record you want. Exact key text and banner details vary by host. A non-zero exit status here means check the address, port and service before touching the timeout.
Write the first result to a new temporary filename. > creates or replaces its destination, so never point it at an existing trusted file until the keys inside are verified:
$ umask 077
$ ssh-keyscan -T 5 -t ed25519 server.example.org > server.example.org.scan
$ test -s server.example.org.scan
$ sed -n '1,3p' server.example.org.scan
umask 077 affects files created by this shell, keeping the scan readable only by its owner. The scan holds public keys, but hostnames, network layout and aliases can still be worth something to an attacker. That test command stays silent on success and fails if the file is empty.
Never replace ~/.ssh/known_hosts or /etc/ssh/ssh_known_hosts with this output as a shortcut: those files drive future SSH trust decisions. Replaced one by accident? Recover it from backup or configuration management rather than trying to infer the old key from the new scan.
Inspect a key fingerprint before installing it. The scan itself gives you no independent comparison, so ask the server owner or use a console or deployment record:
$ ssh-keygen -lf server.example.org.scan
256 SHA256:REPLACE_WITH_TRUSTED_FINGERPRINT server.example.org (ED25519)
Compare the displayed fingerprint against the trusted value, key type and host identity all together. That leading number is the key size reported by ssh-keygen. The placeholder above is deliberately not a real fingerprint, so only swap it in your own notes or comparison process.
Checkpoint: stop if the fingerprint is missing, unexpected, or came from the same network path you are trying to validate in the first place. Never use ssh-keyscan output to silence an SSH warning without understanding why it appeared.
For repeatable collection, keep one host or address per line in a separate input file:
$ printf '%s\n' server.example.org 192.0.2.25 > ssh_hosts
$ ssh-keyscan -T 5 -t ed25519 -f ssh_hosts > ssh_hosts.scan
$ wc -l ssh_hosts.scan
The -f input can hold hostnames, addresses, CIDR ranges, or an address followed by comma-separated aliases. A CIDR range scans every address inside it, so check the range before you run it: large or poorly bounded ranges create noise, load and connection attempts you did not plan for. Keep the scan output separate until every key has been reviewed.
Add -4 or -6 when name resolution returns an address family you do not intend to query, and -p 2222 when the SSH service listens on a non-standard port. The port changes where the command connects; it never changes the host key's identity.
Once you have a trusted baseline, compare a new scan against it. Sorting keeps the comparison stable even when the scan finishes hosts in a different order each time:
$ ssh-keyscan -T 5 -t ed25519 -f ssh_hosts | sort -u > ssh_hosts.current
$ diff -u ssh_known_hosts ssh_hosts.current
No output from diff means the files match. Added, removed or changed lines all need investigating: a changed key can mean a planned rebuild, a host replacement, a hostname resolving elsewhere now, or an attack. Confirm the change independently before you update the baseline, and keep the old file untouched while you investigate so it stays useful as evidence and a rollback reference.
By default, output suits an SSH known-hosts file directly. Add -H to hash hostnames and addresses in that output; hashed names stay usable by SSH while disclosing less if the file gets copied somewhere it should not.
$ ssh-keyscan -H -T 5 -t ed25519 server.example.org
Use -D when you specifically need SSHFP DNS records instead of known-hosts lines:
$ ssh-keyscan -D -O hashalg=sha256 -T 5 -t ed25519 server.example.org
SSHFP records only help if your DNS and SSH verification process is actually configured to use them. Never publish scan output into DNS without validating the key and following your own DNS change controls first. -O currently accepts hashalg=sha1 or hashalg=sha256; leave it off and the command prints both.
-H protects names in output; it never verifies the keys themselves.