You connect to the same box six times a day. Each time you type ssh deploy@203.0.113.10, or worse, you scroll up through your shell history hunting for the last time you typed it, because nobody memorizes an IP address on purpose.
There is a file whose entire job is to stop this. It is ~/.ssh/config, and it has been sitting in your home directory’s blueprint the whole time, empty.
We are going to fill it in. Then ssh web1 will mean exactly what ssh deploy@203.0.113.10 meant, and you will never type the long version again.
The block
Create ~/.ssh/config (it does not exist by default) and paste this, edited to your actual hosts:
# ~/.ssh/config
Host web1
HostName 203.0.113.10
User deploy
Host db1
HostName 10.0.0.5
User postgres
ProxyJump web1
Host *
ServerAliveInterval 30
ServerAliveCountMax 3
Host web1 is the nickname you type. HostName is where it actually goes. User is who you log in as. That is the whole pattern — a label, a destination, an identity — and once it is written down, ssh web1 carries all three.
ssh is picky about permissions on this file. If it is group- or world-readable, ssh ignores it without much of an apology. Lock it down:
chmod 600 ~/.ssh/config
You will know it worked
Here is the trick that makes editing this file safe: ssh -G resolves a host and prints the settings ssh would use — without connecting to anything. No network, no login, only the answer to “what does this nickname expand to?”
$ ssh -G web1
user deploy
hostname 203.0.113.10
port 22
serveraliveinterval 30
That is real captured output from the block above. web1 resolved to user deploy at 203.0.113.10, and it picked up serveraliveinterval 30 from the Host * block at the bottom — more on that in a second. If ssh -G web1 prints hostname web1 instead of the real address, the nickname didn’t match: check spelling and indentation (the settings under a Host line must be indented).
The line that kills bastion gymnastics
db1 has no public address. To reach it you first SSH to web1, then SSH onward to 10.0.0.5 from there. The old way to automate that was a ProxyCommand with netcat, a string of arguments nobody remembered.
ProxyJump web1 is the modern one-liner that replaces it. It tells ssh: to reach this host, hop through web1 first. Watch it resolve:
$ ssh -G db1
user postgres
hostname 10.0.0.5
proxyjump web1
Now ssh db1 transparently tunnels through web1 and lands you on the database box as postgres. One word of config, one command to connect, zero netcat.
The part where it broke
Here is the failure we left in, because it is the one that actually costs you an afternoon.
ssh config is first-match-wins. For each setting, ssh walks the file top to bottom and keeps the first value it sees. This is the opposite of how most config files work, and it is the opposite of what your brain expects.
So this looks fine and is wrong:
# WRONG — Host * is at the top
Host *
User admin
Host web1
HostName 203.0.113.10
User deploy
You’d expect web1 to log in as deploy. It doesn’t:
$ ssh -G web1
user admin
The Host * block matched web1 first, set User to admin, and the later User deploy was ignored — first value wins, the specific one came too late. You’d connect as the wrong user and not know why until the permissions errors started.
Flip the order so the general wildcard sits at the bottom, after every specific host:
# RIGHT — Host * is at the bottom
Host web1
HostName 203.0.113.10
User deploy
Host *
User admin
$ ssh -G web1
user deploy
Now web1 matches its own block first and gets deploy; the Host * block only fills in settings nobody more specific claimed. That is why ServerAliveInterval lives in the bottom Host * — it is a sensible default for every host (it sends a keepalive every 30 seconds so your session survives a flaky connection), and putting it last means any host can still override it.
The rule, stated plainly: specific hosts first, Host * last. Both versions above were run through ssh -G; the outputs are real.
The honest accounting
This saves you the length of an IP address per connection, times however many times a day you connect. Like every hack here, the per-use savings round to nearly nothing.
The real win is the two that don’t show up in keystroke math: you stop fat-fingering octets, and ProxyJump turns a two-hop bastion dance into a single ssh db1. The config file isn’t faster so much as it is correct by default — the right user, the right host, the right tunnel, every time, because you wrote it down once instead of retyping it forty times and getting it wrong on the thirty-ninth.
Name your servers. Put the wildcard last. Then go type ssh web1 and enjoy the four letters.