Sample output
user ada
hostname 10.0.4.17
port 2222
identityfile ~/.ssh/id_ed25519_work
proxyjump bastion
This came from a config with a Host devbox block setting User ada, HostName, IdentityFile, and ProxyJump, followed by a Host * block setting User deploy and Port 2222. The user is ada because the first value found wins, and devbox came first. The port is 2222 because devbox never set one, so the catch-all filled it in. If the server only listens on 22, this line is your bug, and you found it without a single connection attempt.
When you would reach for it
A connection that worked yesterday now asks for a password, logs in as the wrong user, or times out on a port you never chose. Your config has grown to a few hundred lines with wildcards, Include files, and a Host * block someone pasted from a blog post, and reading it top to bottom no longer tells you what ssh will do. Ask ssh instead. It is also the check to run before handing a host alias to rsync, scp, or git, since they all go through the same config.
Gotchas
- For each option, the first value obtained wins and later matches are ignored. That is the reverse of most config formats, where the last line overrides. Put specific
Hostblocks at the top andHost *at the bottom, or your catch-all silently beats everything below it. The-Goutput shows the winner, so a wrong value there means an earlier block claimed it. - The output tells you what won, not where it came from. Add
-vto see which lines applied:ssh -vG devboxprints lines like/home/ada/.ssh/config line 7: Applying options for *to stderr before the dump, which points at the block to fix. -Gis not a dry run forMatch exec. The command inMatch ... exec "..."actually runs during evaluation, because ssh needs its exit status to decide whether the block applies. Keep those commands side-effect free.Match hostcompares against the name afterHostNamehas been substituted, soMatch host devboxnever fires oncedevboxpoints at10.0.4.17. UseMatch originalhost devboxto test the name you typed.-Gis the fastest way to see which one you have.- On Alpine the default
sshmay be Dropbear’s client, which has no-G. Installopenssh-clientto get the OpenSSH one. macOS 15 ships OpenSSH, so the flag works out of the box.
Variants
$ ssh -G -o Port=22 devbox | grep '^port '
Test an override without touching the file. Options given on the command line beat anything in the config, and -G shows the result
$ diff <(ssh -F /dev/null -G devbox) <(ssh -G devbox)
Every setting your config files change from the compiled-in defaults. -F /dev/null skips both ~/.ssh/config and the system-wide /etc/ssh/ssh_config, which on Debian quietly turns on HashKnownHosts and SendEnv LANG LC_*. Process substitution feeds both dumps to diff without a temp file
$ ssh -G devbox | awk '$1 == "proxyjump" {print $2}' | xargs ssh -G | grep -E '^(user|hostname|port) '
Resolve the jump host too. A ProxyJump alias goes through the same config, so a bad port on the bastion breaks the connection to devbox even when the devbox block is correct