Overview

~/.ssh/config gives each host an alias with its own user, key, port, and proxy. For each directive the first value found wins, so put specific Host blocks before Host *. Keep the file private: chmod 600 ~/.ssh/config and chmod 700 ~/.ssh. Generate keys with ssh-keygen -t ed25519 (Ed25519 is the default type); certificate commands are in openssl-commands.

Host blocks

Give every host an alias with an explicit key and IdentitiesOnly yes.

DirectiveExampleEffect
HostHost myserverAlias you type; accepts *, ?, and !negation patterns.
HostNameHostName 203.0.113.7Real host or IP.
User, PortUser deploy, Port 2222Remote account and port.
IdentityFileIdentityFile ~/.ssh/myserver_ed25519Private key to use.
IdentitiesOnlyIdentitiesOnly yesOffer only the listed key, not every key in the agent.
Host myserver
  HostName 203.0.113.7
  User deploy
  IdentityFile ~/.ssh/myserver_ed25519
  IdentitiesOnly yes

Jump hosts

ProxyJump replaces the older ProxyCommand ssh -W %h:%p. Chain hosts with commas.

Host internal-db
  HostName 10.0.1.50
  User postgres
  ProxyJump bastion          # or: ProxyJump bastion1,bastion2

On the command line: ssh -J bastion internal-db.

Connection reuse

Enable multiplexing so repeated ssh and scp calls skip the handshake.

Host *
  ControlMaster auto
  ControlPath ~/.ssh/ctrl/%C       # %C is a hash, so the socket path stays short
  ControlPersist 10m

Create the directory first with mkdir -p ~/.ssh/ctrl. Later ssh and scp runs to the same host skip the handshake. Check or close a master with ssh -O check <host> and ssh -O exit <host>.

Safe defaults

Set these under Host *, then override per host.

DirectiveValueReason
AddKeysToAgentyesLoad a key into ssh-agent on first use.
ForwardAgentno (default)A compromised remote can use a forwarded agent; prefer ProxyJump.
ServerAliveInterval60Keepalive every 60 s (default 0 sends none).
ServerAliveCountMax3 (default)Disconnect after three missed keepalives.
StrictHostKeyCheckingaccept-newTrust new hosts, reject changed keys; safer than no.
HashKnownHostsyesHash hostnames in known_hosts (default no).

Include and Match

Split config by context with Include and Match instead of one huge file.

DirectiveExampleEffect
IncludeInclude ~/.ssh/config.d/*Pull in other files; relative paths are under ~/.ssh.
MatchMatch host *.example.com user deployApply directives only when the conditions hold.
Match execMatch exec "test -f ~/.work"Condition on a command’s exit status.

Place Include before any Host or Match line. After one, it is conditional on that block.

Gotchas

Avoid these; each breaks matching or exposes credentials.

GotchaFix
A broad Host * placed first overrides later specific blocks.Order blocks specific first, defaults last.
ForwardAgent yes under Host * exposes your agent on every server.Enable it per trusted host only.
A stale ControlMaster socket makes ssh fail with a socket error.ssh -O exit <host> or delete the socket.
Without IdentitiesOnly, many agent keys can exhaust the server’s MaxAuthTries.Add IdentitiesOnly yes with an explicit IdentityFile.
A config writable by others, or a private key readable by others, is rejected.Fix permissions as in the overview.