What is in a config file
Before you move a config, know what each part means, because only some of it describes servers:
Include config.d/*
Host web
HostName 203.0.113.10
User deploy
Port 2222
IdentityFile ~/.ssh/id_ed25519_work
ProxyJump bastion
LocalForward 5433 localhost:5432
Host *
ServerAliveInterval 60
Host webis a server: a name you type, with its address and settings.Host *and other patterns such as*.example.comare not servers. They add defaults to every host they match.Includepulls in other files, here~/.ssh/config.d/*, as if they were pasted in that place.ProxyJumpand theForwardlines link servers to each other and to tunnels.
For each option, ssh keeps the first value it reads, from all matching blocks. The SSH config file guide explains this rule with examples.
List every host, Include files too
A quick grep Host misses included files and mixes servers with patterns. This lists only real names, from the main file and the included ones:
awk 'tolower($1)=="host" { for (i = 2; i <= NF; i++) if ($i !~ /[*?!]/) print $i }' ~/.ssh/config ~/.ssh/config.d/*
web
bastion
Change the second path to match your own Include lines, or drop it if you have none. A name that shows up twice is defined in two places, and only the first block's values win for each option.
Check each host with ssh -G
ssh -G prints the final settings for a host, with every file and pattern applied, and does not connect. This is the truth an import should match:
ssh -G web | grep -E '^(hostname|user|port|identityfile|proxyjump|localforward|remoteforward|dynamicforward) '
user deploy
hostname 203.0.113.10
port 2222
localforward 5433 [localhost]:5432
identityfile ~/.ssh/id_ed25519_work
proxyjump bastion
Look for surprises: a user that comes from Host *, a key path that does not exist, or a jump host that is not in your list. To check that each key file is really there:
ls -l ~/.ssh/id_ed25519_work ~/.ssh/id_ed25519_work.pub
Jump hosts have their own guide, ProxyJump and jump host examples, and forwards are explained in SSH tunnels: local, remote and dynamic.
Back up, then export to CSV if you need to
Keep a copy of everything an import reads, so you can compare later and go back if needed:
mkdir -p ~/ssh-backup
cp -p ~/.ssh/config ~/.ssh/known_hosts ~/ssh-backup/
cp -rp ~/.ssh/config.d ~/ssh-backup/
Some tools, and some teams, work from a spreadsheet. This loop turns every host into one CSV line with the values ssh really uses, in a common layout with columns for groups, tags and passwords left empty:
{
echo 'Groups,Label,Tags,Hostname/IP,Protocol,Port,Username,Password'
for h in $(awk 'tolower($1)=="host" { for (i = 2; i <= NF; i++) if ($i !~ /[*?!]/) print $i }' ~/.ssh/config ~/.ssh/config.d/*); do
ssh -G "$h" | awk -v h="$h" '$1=="hostname"{n=$2} $1=="port"{p=$2} $1=="user"{u=$2} END{print ","h",,"n",ssh,"p","u","}'
done
} > hosts.csv
Groups,Label,Tags,Hostname/IP,Protocol,Port,Username,Password
,web,,203.0.113.10,ssh,2222,deploy,
,bastion,,198.51.100.5,ssh,22,admin,
Change the paths in the loop as you did for the host list. Fill in groups such as Acme and tags such as prod in a spreadsheet before you import. Delete the file when you are done if you added passwords to it.
Bring known_hosts along
Your known_hosts holds the fingerprints you have already accepted. Importing it means the first connection from the new tool does not ask you to trust each server again. To check that a host is in it:
ssh-keygen -F 203.0.113.10
ssh-keygen -F '[203.0.113.10]:2222'
A host on a port other than 22 is saved with brackets and the port, as in the second line. If HashKnownHosts is on, names are hashed, and only a search like this finds them. More in known_hosts explained.
After the import
- Compare a few servers with the
ssh -Goutput: address, port, user, key and jump host. - Connect to one server of each kind: a direct one, one behind a jump host, one with a tunnel.
- Keep the original file for scp, rsync and git, which still read it. Importing copies the settings, it does not change
~/.ssh/config. - Sort the result into groups and tags, as in how to manage many SSH servers.
The steps for the app itself are in the import hosts documentation.
Questions
What is an SSH config manager?
An app that stores the same things as ~/.ssh/config, such as addresses, users, ports, keys, jump hosts and tunnels, as saved servers you edit in a form and sort into groups, instead of blocks in a text file.
Are Include files imported with ~/.ssh/config?
They should be, because ssh reads them as part of the file. Before you import, check that ssh -G shows the settings that come from the included files, so you know what to expect.
Do Host * defaults apply to imported servers?
In ssh, every matching block applies and the first value wins, so a server gets the Host * values it did not set itself. ssh -G shows that final result for each host.
Can I import SSH hosts from a CSV file?
Yes, if the manager reads CSV. A common layout is Groups, Label, Tags, Hostname/IP, Protocol, Port, Username and Password, one server per line.
Sources
- ssh_config(5), OpenBSD manual
- ssh(1), the -G option, OpenBSD manual
- ssh-keygen(1), the -F option, OpenBSD manual
- OpenSSH 7.3 release notes, Include