esc
Anthology / Yagnipedia / SSH Config

SSH Config

The file that knows where everything is and how to get there, written in a language that predates empathy
Tool · First observed 1995 (OpenSSH), though the config file format suggests it was designed in 1974 and never updated · Severity: Essential (every developer has one; few understand theirs)

SSH Config (~/.ssh/config) is the file that maps hostnames to connection parameters. It is the reason you can type ssh alpha instead of ssh -i ~/.ssh/id_ed25519_orbstack -p 2222 [riclib](/wiki/riclib)@192.168.139.66 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null. It is the difference between using SSH and suffering SSH.

The Format

SSH config is a series of Host blocks, each defining how to connect to a machine:

Host alpha
    HostName 192.168.139.66
    User riclib
    IdentityFile ~/.ssh/id_ed25519

Now ssh alpha works. Three lines replaced twenty flags. The file is plain text. The syntax is Key Value with no equals sign, no quotes (usually), no colons, no YAML, no JSON, no TOML. It predates all of them. It will outlive all of them.

The ProxyJump

The most powerful and most confusing directive is ProxyJump — SSH through an intermediate host:

Host alpha-via-mac
    HostName 192.168.139.66
    ProxyJump mac

This tells SSH: connect to mac first, then from mac connect to alpha. The intermediate hop is transparent. You type ssh alpha-via-mac and you’re on alpha. The connection bounced through mac. You didn’t notice. SSH didn’t mention it.

ProxyJump is how you reach machines behind NAT without port forwarding. It is also the thing that Tailscale made unnecessary, because Tailscale gives every machine a stable IP that every other machine can reach directly. ProxyJump solves the problem of machines being unreachable. Tailscale solves the problem of machines being unreachable by making them reachable.

THE CONFIG FILE IS A MAP
OF DOORS AND HALLWAYS

PROXYJUMP IS THE HALLWAY
THROUGH ANOTHER ROOM

TAILSCALE IS THE HALLWAY
THAT GOES DIRECTLY THERE

THE BEST HALLWAY
IS THE ONE THAT DOES NOT
REQUIRE A MAP

🦎

The Archaeology

Every developer’s SSH config is an archaeological record. The oldest entries are from the first job. The newest entries are from this morning. Between them: machines that no longer exist, jump hosts for companies you left three years ago, port numbers that made sense once, and comments like # TODO: fix this that will never be fixed because the machine they refer to was decommissioned in 2019.

# Old AWS bastion (do we still have this?)
Host bastion-prod
    HostName 54.x.x.x
    User ubuntu
    IdentityFile ~/.ssh/legacy-aws.pem

# I think this was the staging server?
Host staging-maybe
    HostName 10.0.3.47
    ProxyJump bastion-prod
    # NOTE: key might be rotated

These entries are never deleted. Deleting an SSH config entry requires certainty that the machine is gone, and certainty requires checking, and checking requires connecting, and connecting requires the SSH config entry you were about to delete. The circularity is structural.

The Tailscale Simplification

Before Tailscale, a typical SSH config for reaching OrbStack VMs from multiple locations required ProxyJump entries, conditional includes, and the quiet acceptance that the phone couldn’t reach anything.

After Tailscale:

Host alpha
    HostName alpha

Or nothing at all, because Tailscale SSH with --ssh handles authentication directly. The SSH config entry becomes optional. The hostname resolves via MagicDNS. The authentication happens via Tailscale’s identity provider. The config file shrinks. The archaeology slows.

The Mosh Complication

SSH config works for SSH. It does not work for Mosh. Mosh uses SSH only for the initial handshake — it reads the SSH config to find the host and authenticate — but then switches to UDP. The ProxyJump directive doesn’t help mosh’s UDP traffic. The carefully constructed hallway of intermediate hosts applies only to the TCP handshake. The actual connection, the part that matters, the part that makes mosh survive cellular handoffs, goes direct.

This means mosh needs direct UDP reachability between client and server. Which means Port Forwarding or Tailscale. Which is another way of saying: SSH config solves half the problem, and the half it doesn’t solve is the important half.

Measured Characteristics

Lines in a typical developer's SSH config:               20-200
Lines that are still relevant:                           60%
Lines that refer to machines that no longer exist:       25%
Lines that are comments saying "TODO":                   15%
TODO comments that will be addressed:                    0%
Time saved by SSH config vs typing flags:                ~8 seconds per connection
Connections per day:                                     10-50
Annual time saved:                                       ~20 hours
Entries made unnecessary by Tailscale:                   most of the ProxyJump ones
Entries that will be deleted:                            none (see circularity)

See Also