Working with SSH connections means regularly interacting with the ~/.ssh/known_hosts
file, which stores fingerprints of all hosts you've connected to. For developers managing multiple servers and services, this file can become:
- Difficult to read with long entries
- Hard to maintain without context
- Challenging to debug when entries conflict
The OpenSSH known_hosts format (RFC 4253) defines the file structure as:
[hostname_or_ip] ssh-keytype base64-encoded-key
Example entry:
github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
While the specification doesn't mention comments, some developers report partial success with:
# This is a test comment github.com ssh-rsa AAAAB3NzaC...[rest of key]
However, this behavior is inconsistent across SSH implementations and versions. Some clients might:
- Ignore the comment line completely
- Fail to parse the file
- Strip comments during automatic updates
For better known_hosts management:
1. External Documentation
# Maintain a separate hosts-documentation.md file with: - github.com - Primary code hosting - 192.168.1.100 - Jenkins build server - deploy.prod - Production deployment target
2. Hashed Hostnames with Context
When using hashed hostnames (HashKnownHosts yes
in ssh_config), maintain a separate mapping:
# ~/ssh_hosts_mapping |1|JfKT6hHt7s6L7vCvJQ3J2VqZYE=|oNQHSo5XbG7VxHwu0X3xZJdR0= github.com |1|b7qZl5JtZ5pWkHZ5XkJtZ5pWk=|d5XkJtZ5pWkHZ5XkJtZ5pWk= jenkins.internal
3. Custom Management Script
Create a wrapper script for known_hosts management:
#!/bin/bash # ssh-host-manager case "$1" in add) echo "# Added $(date): $2" >> ~/.ssh/known_hosts.context ssh-keyscan $2 >> ~/.ssh/known_hosts ;; list) paste ~/.ssh/known_hosts.context ~/.ssh/known_hosts ;; *) echo "Usage: $0 {add|list} [host]" ;; esac
- Use
ssh-keyscan
to bulk add hosts - Regularly clean stale entries with
ssh-keygen -R hostname
- Consider version controlling your known_hosts file
- Implement host aliases in ~/.ssh/config for readability
For large teams:
# Puppet manifest example: file { '/etc/ssh/ssh_known_hosts': ensure => present, content => template('module/ssh_known_hosts.erb'), mode => '0644', }
Where the ERB template can include structured comments in a way that doesn't interfere with SSH operations.
The ~/.ssh/known_hosts
file follows a strict format where each line represents a known host entry with this structure:
[hostname_or_ip] ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFJZ...
While the SSH protocol specification (RFC 4251) doesn't explicitly mention comment support in known_hosts, most OpenSSH implementations allow comments using the hash symbol (#) at the beginning of lines:
# Personal development servers dev1.example.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQ... # Production cluster 192.168.1.100 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI...
When you need inline comments (within host entries), consider these approaches:
1. Using host aliases:
# Jenkins_CI_server jenkins.ci.example.com ssh-rsa AAAAB3Nz...
2. Creating a separate mapping file:
# ~/.ssh/host_comments.map host1=Primary database server host2=Staging environment
For large environments, you might want to structure your known_hosts like this:
################################ # AWS US-EAST-1 REGION SERVERS # ################################ ec2-54-123-45-67.compute-1.amazonaws.com ssh-rsa AAAAB... ############################# # LOCAL DEVELOPMENT SERVERS # ############################# dev-vm1 ssh-ed25519 AAAAC3Nza...
Here's a Python script to parse and display annotated known_hosts:
import re def parse_known_hosts(path): with open(path, 'r') as f: for line in f: line = line.strip() if line.startswith('#'): print(f"COMMENT: {line[1:]}") elif line: host, keytype, key = line.split()[:3] print(f"HOST: {host} ({keytype})") parse_known_hosts('/home/user/.ssh/known_hosts')
Combine comments with SSH config for maximum readability:
# ~/.ssh/config Host dev-server # Primary development box HostName 192.168.1.50 User devuser Host prod-db # MySQL production primary HostName db1.prod.example.com User admin