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.
| Directive | Example | What it does |
|---|---|---|
Host | Host myserver | Block label; also the alias you type. Accepts * and ? wildcards. |
HostName | HostName 1.2.3.4 | Real hostname or IP to connect to. |
User | User deploy | Remote username; avoids user@host typing. |
Port | Port 2222 | Non-default port. |
IdentityFile | IdentityFile ~/.ssh/myserver_ed25519 | Path to the private key. |
IdentitiesOnly | IdentitiesOnly yes | Use 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)
| Directive | Example | Effect |
|---|---|---|
ProxyJump | ProxyJump bastion | Connect through the named jump host. Chains to another Host block. |
ProxyJump (chain) | ProxyJump bastion1,bastion2 | Hop through two bastions in order. |
ProxyCommand | ProxyCommand ssh -W %h:%p bastion | Legacy 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)
| Directive | Example | Effect |
|---|---|---|
ControlMaster | ControlMaster auto | Create or reuse a multiplexed connection. |
ControlPath | ControlPath ~/.ssh/ctrl/%r@%h:%p | Socket file path for the master connection. |
ControlPersist | ControlPersist 10m | Keep 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
| Directive | Recommended value | Reason |
|---|---|---|
AddKeysToAgent | yes | Load key into ssh-agent on first use; avoids repeated passphrase prompts. |
ForwardAgent | no (default) | Only enable for trusted intermediate hosts. Agent forwarding exposes your agent socket on the remote. |
ServerAliveInterval | 60 | Send keepalive every 60 s to prevent idle disconnects. |
ServerAliveCountMax | 3 | Disconnect after 3 missed keepalives. |
StrictHostKeyChecking | accept-new | Accept new host keys but reject changed ones. Safer than no. |
HashKnownHosts | yes | Hash 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
| Pattern | Example | Effect |
|---|---|---|
| Wildcard host | Host *.example.com | Apply directives to all subdomains. |
| Negation | Host * !bastion | Apply to all except the bastion. |
Include | Include ~/.ssh/work_config | Source another config file; useful for work/personal split. |
Match blocks | Match 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/configmust be600; the directory must be700. SSH ignores the config or refuses the key otherwise. ForwardAgent yesin aHost *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.ControlPersistcan hide failures. If the master connection died, subsequentsshcalls fail with a cryptic socket error. Runssh -O exit <alias>to close a stale master.IdentitiesOnly yesprevents SSH from trying all keys in the agent. Without it, a server withMaxAuthTries 3locks you out before the right key is tried if the agent holds many keys.Includepaths do not expand~in all SSH versions. Use the full absolute path or rely on the%dtoken (%d/.ssh/work_config).HashKnownHosts yesmakesssh-keygen -R hostnameunable to remove the entry by hostname. Usessh-keygen -R <ip>or editknown_hostsdirectly.