.Ssh

SSH Client Configuration with ~/.ssh/config

Learn how to configure reusable SSH host aliases, users, ports, keys, jump hosts, forwarding, Git identities, security settings, and troubleshooting in ~/.ssh/config.

The OpenSSH client is a command-line tool for encrypted remote login, command execution, tunneling, and file transfer. Before opening a connection, it reads client configuration and combines those settings with command-line options and built-in defaults.

The usual per-user configuration file is ~/.ssh/config. The ~ character means your home directory. This file controls how your local client connects outward. It is different from the server-side sshd_config, which controls an SSH server and is commonly maintained by an administrator.

Why use ~/.ssh/config?

Without a configuration profile, a connection may require several options:

ssh -p 2222 -i ~/.ssh/id_ed25519_app deploy@server.example.net

A Host alias stores those choices under a memorable name:

Host app-admin
    HostName server.example.net
    User deploy
    Port 2222
    IdentityFile ~/.ssh/id_ed25519_app
    IdentitiesOnly yes

You can then connect with:

ssh app-admin

The alias is local to your SSH client. It does not create a DNS record or change the remote server's name.

Create and secure the configuration

Create the directory and file if necessary:

mkdir -p ~/.ssh
touch ~/.ssh/config
chmod 700 ~/.ssh
chmod 600 ~/.ssh/config

Edit the file with a text editor, for example:

nano ~/.ssh/config

The directory permission 700 allows only your account to access the directory. The file permission 600 allows only your account to read and write the configuration. Restricting access matters because the file can reveal usernames, internal hostnames, key paths, forwarding rules, and connection architecture. Private keys should also be protected from unrelated local users and should normally have a passphrase.

Do not put passwords, API tokens, secret text, or private-key contents in the configuration file. Use key-based authentication and store private keys separately, such as Ed25519 keys or other supported key types.

Configuration syntax

SSH configuration uses whitespace-separated directive and value pairs. Indentation is optional but improves readability. A number sign begins a comment:

# Administrative application server
Host app-admin
    HostName server.example.net
    User deploy

A Host declaration starts a block. Its directives apply to the connection name being evaluated until another Host declaration begins. A block can match either an alias or a hostname pattern.

Patterns, wildcards, and negation

The wildcard * matches any sequence of characters, and ? matches one character. A pattern can cover a group of hosts:

Host *.lab.example.net
    User student
    ServerAliveInterval 30

A negated pattern begins with !. This lets a broad block exclude a particular name:

Host *.example.net !production.example.net
    User developer

Use broad patterns carefully. Descriptive aliases and comments make long-lived configurations easier to review.

Matching and precedence

In practical terms, SSH considers explicit command-line choices before configuration-file choices, then user configuration, system-wide client configuration, and built-in defaults. Within matching configuration blocks, OpenSSH commonly uses the first value obtained for an option. Therefore, place more specific rules before broad wildcard rules, and do not assume a later block will replace an earlier value.

SourceExamplesWhen it is usedOrdering consideration
Command-line optionsssh -p 2222 host, ssh -i key hostOne-off or script-specific choicesUsually takes precedence over file settings
User configuration~/.ssh/config and included filesPersonal reusable profilesSpecific matching blocks should precede broad ones
System-wide client configurationTypically /etc/ssh/ssh_configDefaults supplied by the operating system or administratorIts interaction with user settings depends on the option and parsing order; inspect the effective result
Built-in defaultsOpenSSH defaultsWhen no other source supplies a valueLowest-level fallback

When an option appears to be ignored, use ssh -G alias rather than guessing about precedence.

Basic host profiles

The most useful directives are:

DirectiveWhat it controlsTypical useSecurity or operational note
HostA pattern or local aliasStarts a reusable profileUse clear names and narrow patterns
HostNameActual DNS name or IP addressMaps an alias to its destinationCheck the address carefully for sensitive systems
UserRemote account nameAvoids repeating user@hostUse the least-privileged suitable account
PortSSH service portStores a non-default portA custom port is not a substitute for authentication security
IdentityFilePrivate key pathSelects a key for a hostProtect the key and do not expose its contents
IdentitiesOnlyWhether to limit offered identitiesPrevents unrelated agent keys from being triedUseful when servers enforce authentication-attempt limits
ProxyJumpIntermediate SSH hostReaches private networks through a bastionRestrict and audit jump hosts
ServerAliveIntervalSeconds between client SSH-level probesDetects an inactive network pathChoose a reasonable interval
ServerAliveCountMaxUnanswered probes allowedDetermines when to close a dead sessionHigher values tolerate outages but delay detection
StrictHostKeyCheckingHandling of new or changed host keysControls verification behaviorDo not disable verification globally
UserKnownHostsFileKnown-hosts database pathUses a dedicated file for automation or temporary environmentsVerify keys before trusting them
ControlMasterConnection multiplexing modeShares one connection among sessionsProtect the control socket
ControlPathMaster connection socket pathNames the multiplexing socketUse a private directory and a collision-resistant template
ControlPersistHow long a master remains after logoutSpeeds repeated connectionsPersistent sessions have security and resource implications
IncludeAdditional configuration filesSplits large configurationsReview included files as part of the configuration

SSH keys and identity selection

An SSH key pair consists of a private key and a public key. The client proves possession of the private key; the server has previously authorized the matching public key. Never paste private-key contents into ~/.ssh/config or send them to another person.

Host work-git
    HostName git.example.com
    User git
    IdentityFile ~/.ssh/id_ed25519_work
    IdentitiesOnly yes

Host personal-git
    HostName git.example.com
    User git
    IdentityFile ~/.ssh/id_ed25519_personal
    IdentitiesOnly yes

These aliases point to the same service but select different identities. This is useful for separate organizations, accounts, or repository groups. An ssh-agent can hold decrypted keys for the client, but if it contains many keys, the server may reject the connection after too many attempts. IdentitiesOnly yes tells the client to use the identities configured for that profile instead of indiscriminately offering agent keys.

Multiple IdentityFile directives can be listed when a server may accept more than one configured identity:

Host multi-key-service
    HostName service.example.net
    IdentityFile ~/.ssh/id_ed25519_work
    IdentityFile ~/.ssh/id_ecdsa_legacy
    IdentitiesOnly yes

Connection reliability and multiplexing

ConnectTimeout limits how long the client waits while establishing a connection. It is useful for unreachable hosts and scripts:

Host app-admin
    ConnectTimeout 10
    ServerAliveInterval 30
    ServerAliveCountMax 3

ServerAliveInterval sends an SSH-level request after the specified idle period. If the server does not respond, ServerAliveCountMax controls how many unanswered requests are tolerated. These settings can detect broken paths and reduce disconnects caused by idle network devices.

TCPKeepAlive is a lower-level TCP behavior. It uses operating-system TCP keepalive mechanisms and is distinct from SSH-level server-alive messages. Neither setting repairs an unstable network; they only help detect or maintain certain connections.

Connection multiplexing allows several SSH sessions to reuse one master connection:

Host *.example.net
    ControlMaster auto
    ControlPath ~/.ssh/control-%r@%h:%p
    ControlPersist 10m

This can make repeated commands faster and reduce repeated authentication. Use a private control-socket location and avoid sharing it with other users. Disable multiplexing for hosts where session reuse is inappropriate.

Host-key verification and known_hosts

A host public key identifies the server endpoint. OpenSSH records trusted keys in a known_hosts file and compares them on later connections. This helps detect impersonation and man-in-the-middle attacks.

StrictHostKeyChecking controls what happens when a key is new or changes. A changed-key warning may indicate a legitimate rebuild, a changed DNS route, or an attack. Verify the new fingerprint through an independent trusted channel before replacing the stored entry. Do not routinely solve warnings by setting StrictHostKeyChecking no.

A dedicated known-hosts file can isolate automation or a temporary environment:

Host test-automation
    HostName test.example.net
    User runner
    UserKnownHostsFile ~/.ssh/known_hosts_automation
    StrictHostKeyChecking yes

Keep the trusted file protected and populate it only with verified keys. See known_hosts for the role of stored host keys.

Jump hosts and proxies

A bastion host, also called a jump host, is a controlled intermediate server used to reach an otherwise private destination. The final destination and the jump host are separate SSH connections.

Host gateway
    HostName bastion.example.net
    User ops
    IdentityFile ~/.ssh/id_ed25519_ops

Host private-app
    HostName 10.20.30.40
    User deploy
    ProxyJump gateway
    IdentityFile ~/.ssh/id_ed25519_app
    IdentitiesOnly yes

Now ssh private-app connects through gateway. Multiple hops can be expressed conceptually as a comma-separated sequence:

Host deeply-private
    HostName 10.30.40.50
    ProxyJump gateway,second-gateway

ProxyCommand is an older or more flexible alternative. It can invoke a helper program or custom transport when ProxyJump does not meet the requirement. Prefer the simpler directive when it is sufficient.

Forwarding and remote workflows

Forwarding creates a tunnel between listening ports. Place forwarding directives in a host profile only when they are needed:

TypeDirectionPrimary directive or command optionExample use caseMain risk
Local forwardingLocal port to a service reachable from the remote sideLocalForward 8080 db.internal:80Open a remote-only web service at local port 8080May expose an internal service to local users
Remote forwardingRemote listening port to a service reachable locallyRemoteForward 9000 localhost:9000Allow a remote system to reach a local development serviceCan expose the local service beyond its intended boundary
Dynamic forwardingLocal SOCKS proxy to destinations requested by applicationsDynamicForward 1080Proxy browser or diagnostic traffic through the SSH hostCan become an uncontrolled proxy if exposed
Host internal-web
    HostName private-app.example.net
    User deploy
    ProxyJump gateway
    LocalForward 8080 web.internal:80

Agent forwarding can let a remote session use keys held by your local ssh-agent without copying private keys. Enable it only for a trusted host and a specific workflow:

Host trusted-admin
    ForwardAgent yes

A compromised remote account could abuse an available forwarded agent, so avoid broad Host * agent-forwarding rules. X11 forwarding is an optional legacy feature for graphical remote sessions and should likewise be enabled only when required.

File transfer and Git

scp and sftp use the same SSH client configuration, so aliases work with them:

sftp app-admin
scp ./release.tar.gz app-admin:/srv/releases/

Git SSH URLs can use an alias as the host portion. The alias selects the corresponding hostname, account, and key:

git clone git@work-git:team/project.git

In this example, Git supplies the remote account git, while work-git selects the profile. A second alias such as personal-git can select a different key for the same Git hosting domain.

Wildcard defaults and included files

Host * applies broadly, so keep its settings conservative:

Host *
    ServerAliveInterval 30
    ServerAliveCountMax 3
    ConnectTimeout 10

Narrower patterns are safer for groups:

Host dev-*
    User developer

Host *.staging.example.net
    User release

Host production.example.net
    User prod-admin
    IdentitiesOnly yes

Put sensitive production settings in an explicit block rather than relying only on broad defaults. Because first-obtained values generally win, place the production block before a wildcard block if both can match.

Large configurations can be split into files:

Include ~/.ssh/config.d/*

For example, separate files can contain personal, work, laboratory, and infrastructure profiles. Ensure included files are readable only by the intended user when they contain sensitive topology or connection details.

Inspect, test, and debug

Test every alias before using it in automation, file transfers, or Git remotes. The -G option prints the effective configuration after matching:

ssh -G app-admin

Inspect values such as hostname, user, port, identityfile, proxyjump, and known-hosts paths. This is the fastest way to find an unexpected wildcard match or an option supplied earlier.

Verbose output shows connection and authentication decisions:

ssh -vvv app-admin

Look for the destination being contacted, matched configuration patterns, identities offered, and the reason authentication or networking failed. Do not paste private keys or sensitive diagnostic data into public reports.

SymptomLikely causeHow to inspectSafe correction
Wrong remote accountIncorrect or inherited UserRun ssh -G aliasSet the intended User in a specific block
Wrong key offeredMany agent keys or incorrect IdentityFileUse ssh -vvv alias and inspect effective identitiesSet IdentityFile and IdentitiesOnly yes
Alias resolves incorrectlyMisspelled HostName or broad wildcard matchUse ssh -G alias and verbose outputCorrect the profile and put specific rules before broad ones
Permission deniedWrong account, key, server authorization, or key permissionsReview verbose authentication output and local permissionsCorrect the account or authorized public key; protect the private key
Host key mismatchRebuilt server, changed route, or possible interceptionVerify the fingerprint independently and inspect known_hostsReplace the key only after confirmation
TimeoutWrong address or port, firewall, or unavailable hostCheck effective hostname, port, and verbose networking outputCorrect destination settings; use a reasonable ConnectTimeout
Jump host failureInvalid gateway profile, routing issue, or different key requirementsTest the gateway separately, then use verbose output for the targetFix each connection leg and keep separate gateway and target profiles

Common editing problems

If changes seem ignored, confirm the file is exactly ~/.ssh/config, check ownership and permissions, inspect included files, and run ssh -G. An earlier matching block or a command-line option may be supplying the value you expected to change. If sessions disconnect after a predictable idle period, investigate network or VPN behavior and consider suitable ServerAliveInterval and ServerAliveCountMax values.

Security checklist

  • Use key-based authentication and protect private keys with restrictive permissions and passphrases.
  • Never store passwords, tokens, or private-key material directly in the configuration.
  • Verify unexpected host-key changes through an independent trusted channel.
  • Do not globally disable host-key verification.
  • Use IdentitiesOnly yes where multiple agent keys could cause authentication confusion.
  • Limit agent forwarding, port forwarding, and X11 forwarding to hosts and workflows that require them.
  • Use explicit settings for sensitive production systems rather than excessively broad wildcards.
  • Protect multiplexing control sockets and included configuration files.

Summary

The per-user OpenSSH client file, ~/.ssh/config, turns repeated command-line options into reusable profiles. Start with Host, HostName, User, Port, and IdentityFile; add IdentitiesOnly when key selection must be strict. Use ProxyJump for bastions, forwarding directives for controlled tunnels, and keepalive or multiplexing options for appropriate operational needs. Validate profiles with ssh -G and ssh -vvv, and treat host-key verification and private-key protection as essential security controls.