Overview

~/.ssh/config gives each host a named alias with its own key, port, and proxy settings. Without it, every connection requires repeating flags on the command line. This card covers the directives that matter most and the patterns that solve common problems. For key generation commands, see openssl-commands.

File permissions matter: chmod 600 ~/.ssh/config and chmod 700 ~/.ssh/.

Host block structure

Each block starts with Host <alias> and applies to any ssh <alias> invocation.

DirectiveExampleWhat it does
HostHost myserverBlock label; also the alias you type. Accepts * and ? wildcards.
HostNameHostName 1.2.3.4Real hostname or IP to connect to.
UserUser deployRemote username; avoids user@host typing.
PortPort 2222Non-default port.
IdentityFileIdentityFile ~/.ssh/myserver_ed25519Path to the private key.
IdentitiesOnlyIdentitiesOnly yesUse only the listed key; skip the agent’s other keys.
Host myserver
  HostName 1.2.3.4
  User deploy
  Port 2222
  IdentityFile ~/.ssh/myserver_ed25519
  IdentitiesOnly yes

ProxyJump (bastion / jump hosts)

DirectiveExampleEffect
ProxyJumpProxyJump bastionConnect through the named jump host. Chains to another Host block.
ProxyJump (chain)ProxyJump bastion1,bastion2Hop through two bastions in order.
ProxyCommandProxyCommand ssh -W %h:%p bastionLegacy fallback; prefer ProxyJump.
Host bastion
  HostName bastion.example.com
  User admin
  IdentityFile ~/.ssh/bastion_ed25519

Host internal-db
  HostName 10.0.1.50
  User postgres
  ProxyJump bastion
  IdentityFile ~/.ssh/internal_ed25519

ssh internal-db automatically tunnels through the bastion without any extra flags.

ControlPersist (connection reuse)

DirectiveExampleEffect
ControlMasterControlMaster autoCreate or reuse a multiplexed connection.
ControlPathControlPath ~/.ssh/ctrl/%r@%h:%pSocket file path for the master connection.
ControlPersistControlPersist 10mKeep master alive 10 minutes after last client disconnects.
Host *
  ControlMaster auto
  ControlPath ~/.ssh/ctrl/%r@%h:%p
  ControlPersist 10m

Create the directory first: mkdir -p ~/.ssh/ctrl. Subsequent ssh and scp to the same host reuse the existing socket with no handshake overhead.

Security and agent directives

DirectiveRecommended valueReason
AddKeysToAgentyesLoad key into ssh-agent on first use; avoids repeated passphrase prompts.
ForwardAgentno (default)Only enable for trusted intermediate hosts. Agent forwarding exposes your agent socket on the remote.
ServerAliveInterval60Send keepalive every 60 s to prevent idle disconnects.
ServerAliveCountMax3Disconnect after 3 missed keepalives.
StrictHostKeyCheckingaccept-newAccept new host keys but reject changed ones. Safer than no.
HashKnownHostsyesHash hostnames in known_hosts; limits exposure if the file leaks.
Host *
  AddKeysToAgent yes
  ForwardAgent no
  ServerAliveInterval 60
  ServerAliveCountMax 3
  StrictHostKeyChecking accept-new
  HashKnownHosts yes

Wildcard and include patterns

PatternExampleEffect
Wildcard hostHost *.example.comApply directives to all subdomains.
NegationHost * !bastionApply to all except the bastion.
IncludeInclude ~/.ssh/work_configSource another config file; useful for work/personal split.
Match blocksMatch exec "test -f ~/.work"Conditional directives based on shell command exit code.
# Personal defaults
Host *
  IdentityFile ~/.ssh/personal_ed25519

# Work overrides (loaded last, so they win for work hosts)
Include ~/.ssh/work_config

Order of evaluation: first match wins for each directive, so put specific blocks before wildcards.

Common gotchas

  • Permissions must be exact. ~/.ssh/config must be 600; the directory must be 700. SSH ignores the config or refuses the key otherwise.
  • ForwardAgent yes in a Host * block forwards your agent to every server you touch. A compromised server can use your agent socket to impersonate you. Enable it per host, not globally.
  • ControlPersist can hide failures. If the master connection died, subsequent ssh calls fail with a cryptic socket error. Run ssh -O exit <alias> to close a stale master.
  • IdentitiesOnly yes prevents SSH from trying all keys in the agent. Without it, a server with MaxAuthTries 3 locks you out before the right key is tried if the agent holds many keys.
  • Include paths do not expand ~ in all SSH versions. Use the full absolute path or rely on the %d token (%d/.ssh/work_config).
  • HashKnownHosts yes makes ssh-keygen -R hostname unable to remove the entry by hostname. Use ssh-keygen -R <ip> or edit known_hosts directly.