Every SSH connection you make gets recorded in your ~/.ssh/known_hosts
file. Over time, especially when working with temporary VMs or cloud instances, this file accumulates obsolete entries that:
- Clutter your SSH configuration
- Potentially cause false positive warnings
- May expose information about your infrastructure
Each entry in known_hosts follows this pattern:
[hostname_or_ip] ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNo...==
The three components are:
- Host identifier (hostname, IP, or hashed value)
- Key type (ssh-rsa, ecdsa-sha2-nistp256, etc.)
- The public key itself
Here's a practical way to audit your known_hosts:
#!/bin/bash
# Check which hosts are still active
CURRENT_HOSTS=$(grep -v '^#' ~/.ssh/known_hosts | awk '{print $1}')
for host in $CURRENT_HOSTS; do
if [[ "$host" == "|1|"* ]]; then
echo "Hashed entry detected: $host"
else
nc -z ${host%:*} ${host##*:} 2>/dev/null && \
echo "Active: $host" || \
echo "Inactive: $host"
fi
done
Use ssh-keygen
to remove entries safely:
# Remove by hostname
ssh-keygen -R example.com
# Remove by IP
ssh-keygen -R 192.168.1.100
# Remove hashed entries (when you only know the original hostname)
ssh-keygen -H -f ~/.ssh/known_hosts -R "old-vm-01"
For more complex management, this Python script helps analyze entries:
import sys
from collections import defaultdict
def parse_known_hosts(file_path):
entries = defaultdict(list)
with open(file_path, 'r') as f:
for line in f:
if line.strip() and not line.startswith('#'):
parts = line.strip().split()
entries[parts[0]].append({
'key_type': parts[1],
'fingerprint': parts[2]
})
return entries
if __name__ == "__main__":
entries = parse_known_hosts(sys.argv[1])
for host, keys in entries.items():
print(f"Host: {host}")
for key in keys:
print(f" Type: {key['key_type']}")
print(f" Fingerprint: {key['fingerprint'][:30]}...")
- Regularly prune entries for decommissioned servers
- Consider using
ssh-keyscan
for bulk additions to new systems - For development environments, use
StrictHostKeyChecking no
temporarily - Back up known_hosts before major cleanups
When hosts are hashed (starting with |1|), you can:
# List all hashed entries
grep '^|1|' ~/.ssh/known_hosts
# Find a specific host's hash
ssh-keygen -H -F example.com
The ~/.ssh/known_hosts
file contains SSH host keys in the following format:
[hostname_or_ip] ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBJ... [hostname_or_ip] ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDfAm4V...
Use this command to search for a specific host:
ssh-keygen -F example.com -f ~/.ssh/known_hosts
Output will show all matching entries:
Host example.com found: line 15 |1|dGhpc2lzYXNhbHR8ClVzZXJ8U2VydmVy|ecdsa-sha2-nistp256 AAAAE2...
If your file uses hashed hostnames (common in newer SSH versions), first view unhashed:
ssh-keygen -H -f ~/.ssh/known_hosts
To delete a specific host key:
ssh-keygen -R example.com -f ~/.ssh/known_hosts
For IP addresses:
ssh-keygen -R 192.168.1.100
Create a backup first:
cp ~/.ssh/known_hosts ~/.ssh/known_hosts.backup-$(date +%Y%m%d)
Then use this script to find inactive hosts:
#!/bin/bash TMPFILE=$(mktemp) CURRENT_HOSTS=$(ssh -G example.com | grep "^hostname" | awk '{print $2}') while read -r line; do host=$(echo "$line" | awk '{print $1}') if [[ "$host" =~ ^\|1\| ]]; then continue # Skip hashed entries fi if ! grep -q "$host" <<< "$CURRENT_HOSTS"; then echo "$line" >> "$TMPFILE" fi done < ~/.ssh/known_hosts mv "$TMPFILE" ~/.ssh/known_hosts
- Regularly audit your known_hosts file (quarterly)
- Use SSH config files to manage connections
- Consider using
StrictHostKeyChecking=accept-new
for test environments - For development VMs, use consistent hostnames/IPs