Do not overwrite active SSH host-key files in one step. Generate replacement keys under new filenames, load old and new identities together, publish the new fingerprints through a trusted channel, and retire the old keys only after every important client class has migrated. That overlap preserves access while OpenSSH clients learn the replacement.
Host-key rotation changes what clients trust about the server; it does not change which users may log in. Confusing those two directions is why many runbooks either rotate the wrong keys or teach users to dismiss a serious host-identity warning.
An SSH host key is the server’s long-lived cryptographic identity. During connection setup, the client verifies that identity against a user or system known_hosts file. A user’s private key and the server’s authorized_keys entry work in the opposite direction: they prove the user to the server.
Rotating ~/.ssh/id_ed25519 therefore does not replace a VPS host key. Editing authorized_keys also leaves the server fingerprint unchanged. OpenSSH normally loads host private keys from root-owned paths below /etc/ssh, while clients remember corresponding public keys by hostname, address, alias and sometimes port.
That distinction matters after a clone. A restored VM can inherit the source machine’s host keys and present the same identity from another address. Voxfor’s isolated Proxmox restore drill treats duplicated SSH identity as part of the recovery boundary. Templates and clones should receive unique host keys before they join a routable network.
Keep the current administrative session open. Confirm console, rescue or provider-side access works independently of SSH, and open a second verified login before changing daemon configuration. Voxfor’s Linux VPS first-login checks use the same second-session principle because an untested recovery path is not a rollback plan.
Inventory the daemon, effective host-key paths and current fingerprints without changing state:
ssh -V
sudo sshd -t
sudo sshd -T | awk '$1 == "hostkey" {print $2}'
sudo find /etc/ssh -maxdepth 1 -type f -name 'ssh_host_*_key.pub' -print
For every active public file, print its SHA-256 fingerprint:
sudo find /etc/ssh -maxdepth 1 -type f -name 'ssh_host_*_key.pub' -print0 | sudo xargs -0 -r -n1 ssh-keygen -lf
Record the hostname, IP addresses, SSH port, aliases, load balancer or bastion path, client owners and existing fingerprints. Include human workstations, CI runners, deployment tools, backup agents, monitoring probes and configuration management. One forgotten noninteractive client can turn a successful human cutover into a failed release hours later.
Routine cryptographic renewal, image de-duplication and migration allow an orderly overlap window. Suspected private-key exposure is different: whoever holds the old private host key may impersonate the server while that key remains trusted. Overlap maintains availability; it does not neutralize a compromised identity.
For suspected exposure, establish fingerprints through a channel the old SSH key cannot impersonate, such as a provider console, authenticated asset database, signed change record or another already trusted management plane. Keep the overlap as short as client coverage permits.
Choose filenames that identify the generation or change ticket. The current OpenSSH ssh-keygen manual supports Ed25519 and RSA host keys; client compatibility determines whether the server needs both. Ed25519 is a compact default for modern OpenSSH clients, while an RSA key using SHA-2 signatures may remain necessary for a documented legacy population.
First prove the proposed paths are unused:
sudo test ! -e /etc/ssh/ssh_host_ed25519_key_20260803
sudo test ! -e /etc/ssh/ssh_host_rsa_key_20260803
Only when both checks return success should the operator generate new files:
sudo ssh-keygen -q -t ed25519 -N '' -C 'VPS host key 2026-08-03' -f /etc/ssh/ssh_host_ed25519_key_20260803
sudo ssh-keygen -q -t rsa -b 3072 -N '' -C 'VPS host key 2026-08-03' -f /etc/ssh/ssh_host_rsa_key_20260803
Confirm ownership, modes and fingerprints immediately:
sudo stat -c '%U:%G %a %n' /etc/ssh/ssh_host_*_key_20260803
sudo ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key_20260803.pub
sudo ssh-keygen -lf /etc/ssh/ssh_host_rsa_key_20260803.pub
Private host-key files must not be group- or world-accessible. Do not email private files, copy them into a ticket or store them with public fingerprints. Publish only the .pub material and its independently verified fingerprint.
The OpenSSH daemon manual permits multiple HostKey directives. Build an explicit list containing every currently active path plus every replacement path. On Ubuntu, a drop-in may be used when the main configuration already includes /etc/ssh/sshd_config.d/*.conf; other distributions may require editing the primary file.
An example overlap file looks like this, but its first two paths must match the inventory from sshd -T:
HostKey /etc/ssh/ssh_host_ed25519_key
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_ed25519_key_20260803
HostKey /etc/ssh/ssh_host_rsa_key_20260803
Write the file with root-only control, then validate both syntax and effective loading:
sudo chmod 600 /etc/ssh/sshd_config.d/05-hostkey-rotation.conf
sudo sshd -t
sudo sshd -T | awk '$1 == "hostkey" {print $2}'
Stop if sshd -t reports an error, an expected current key disappears, or a replacement path is absent from effective output. Correct the file from the held-open session; do not restart the daemon to “see whether it works.”
After clean validation, Ubuntu normally reloads the service with:
sudo systemctl reload ssh
sudo systemctl is-active ssh
sudo journalctl -u ssh --since '-5 minutes' --no-pager
Some distributions name the unit sshd; use the unit already active on that host. A reload keeps established sessions alive, but that is not proof that new handshakes work. Open a fresh connection from a separate terminal and inspect the server fingerprint before closing the recovery session.
OpenSSH 6.8 and later can advertise all loaded host keys through the [email protected] extension. With UpdateHostKeys enabled, a client that successfully authenticates the server through an already trusted key can add replacement keys to its user known_hosts file. The OpenSSH client manual documents the conditions and notes that custom known-hosts settings or DNS verification can change defaults.
Use an explicit one-time client test first:
ssh -o UpdateHostKeys=yes -l admin server.example.com
ssh-keygen -F server.example.com
Compare every newly recorded key with the fingerprint published through the trusted change channel. Repeat for IP addresses, aliases and non-default ports that clients actually use. Port-qualified entries are represented as [hostname]:port, so server.example.com and [server.example.com]:2222 are separate trust records.
Automation deserves a planned update rather than an interactive surprise. Place verified new public keys in the managed known_hosts source used by CI, backup and deployment jobs before old identities disappear. Run one real connection from each material client class and record its result. A green workstation login cannot prove a containerized runner or isolated backup node received the same trust update.
ssh-keyscan into identity proofssh-keyscan is useful for observing which keys an endpoint currently presents:
ssh-keyscan -t ed25519,rsa server.example.com
However, the official ssh-keyscan warning says unverified scan output leaves users vulnerable to man-in-the-middle attacks. Scanning the same network path that produced a warning only tells you what that path served; it does not prove who controls the endpoint.
Likewise, ssh-keygen -R server.example.com removes stored records but does not authenticate the replacement. Use -R only after a separately verified change when a stale entry truly must be removed. Never work around rotation with StrictHostKeyChecking=no or a null UserKnownHostsFile; those settings discard the security property the rotation is meant to preserve.
When the old private key may be stolen, UpdateHostKeys cannot serve as independent proof because its trust is anchored in that old identity. Reach the VPS through provider console access or a separately authenticated path, verify the new fingerprint there, and distribute it through a channel with known ownership.
Voxfor’s private Tailscale SSH architecture can provide a distinct management path when it was established and tested before the incident. Adding a new emergency tool during suspected compromise does not automatically create trustworthy recovery; its installer, account and device approvals need their own verification.
Security teams should also investigate where the old key could have been copied: VM templates, snapshots, backups, image pipelines, support bundles and configuration repositories. Removing one live file does not revoke duplicates elsewhere. Host certificates can reduce per-host pinning at fleet scale, but introducing a host CA is a separate trust migration, not a quick patch inside an active incident.
Define the retirement gate before the overlap begins. A practical gate includes all of the following:
sshd -t passes and effective configuration lists the intended new keys.Remove old HostKey directives from active configuration, validate again, reload, and establish another fresh connection. Preserve old private material only in an approved encrypted incident archive when policy requires it; otherwise remove it from the live host after rollback approval. Do not leave retired files referenced, readable or available for accidental reuse.
For golden images and automated provisioning, generate host identity at first boot and block readiness until uniqueness plus SSH reachability are proven. Voxfor’s cloud-init readiness diagnosis explains why a provisioning tool reporting “done” is weaker than an external service check.
At larger scale, ownership determines the safe workflow. Teams comparing self-managed operations with provider-run change control can use Voxfor’s managed versus unmanaged VPS decision guide to clarify who maintains console access, client inventory, key distribution and incident evidence.
An SSH host key is a private key used by the server to prove its identity during connection setup. Clients store the corresponding public key in known_hosts; user login keys and authorized_keys authenticate people or automation in the opposite direction.
Yes. OpenSSH accepts multiple HostKey directives, allowing old and replacement identities to coexist during a controlled overlap. Validate the complete configuration with sshd -t and confirm effective paths before reloading.
UpdateHostKeys independently verify a replacement key?No. UpdateHostKeys learns additional keys only after the server authenticates with an already trusted host key. It supports graceful rotation, but an independently verified fingerprint is still required when the old private key may be compromised.
ssh-keyscan enough to trust a changed host key?No. ssh-keyscan reports keys presented over the observed network path but does not prove server ownership. Compare scan output with fingerprints obtained through a separately trusted channel.
known_hosts entry not verification?ssh-keygen -R removes old trust data; it does not authenticate whatever key appears next. Verify the replacement fingerprint first, then remove a stale entry only as part of an authorized change.
Keep both generations active long enough for every material human and automated client class to connect and learn or pin the replacement. Suspected compromise requires a shorter, tightly coordinated window because the old private key may still enable impersonation.
A quiet SSH log does not prove that dormant clients migrated. Close the change with old and new fingerprints, effective daemon paths, client-class results, recovery-channel proof, reload timestamps and the exact retirement decision. That record turns the next warning into a verifiable event instead of another invitation to click past security.