SSH Config File: ~/.ssh/config Examples for Linux

Deepak Prasad
Tested on RHEL 10.2 (kernel 6.12)
Package openssh-clients-9.9p1-25.el10_2.x86_64
Applies to Any Linux host with OpenSSH client (openssh-client, openssh-clients)
Privilege Normal user
Scope OpenSSH client configuration in ~/.ssh/config and ssh_config—host aliases, keys, jump hosts, and ssh -G verification. Server hardening in sshd_config, cipher tuning, and general ssh usage are out of scope here.
Related guides Fail2ban for SSH
SSH SOCKS proxy
Kill hung SSH sessions
Reverse SSH port forwarding
Fix SSH no route to host

Stop retyping ssh -i … -p … user@long-hostname.example.com for every server. The OpenSSH client reads ~/.ssh/config and applies Host blocks automatically when you run ssh web or ssh internal. This walkthrough builds that file step by step: aliases, keys, wildcards, bastions, includes, and a quick way to print what SSH actually picked.


Quick reference: SSH config examples

Task Example Host block
Short alias Host webHostName server.example.com, User deploy, Port 22
Private key IdentityFile ~/.ssh/id_ed25519_web plus IdentitiesOnly yes
Jump host ProxyJump bastion or ProxyJump user@bastion.example.com:22
Wildcard defaults Host *.example.com with shared User or IdentityFile
Split files Include ~/.ssh/config.d/*.conf — order specific stanzas before defaults
Reuse one TCP session ControlMaster auto, ControlPath, ControlPersist on Host *
Inspect effective config ssh -G alias (no connection)
Check precedence ssh -p 2222 -G alias — CLI flags override Port in config

What is ~/.ssh/config?

Linux has two SSH configuration families that are easy to mix up:

  • Clientssh, scp, and sftp read ~/.ssh/config (per user) and /etc/ssh/ssh_config (system-wide). Keywords are documented in ssh_config(5).
  • Serversshd reads /etc/ssh/sshd_config (sshd_config(5)). That file controls who may log in, not your personal shortcuts. For server-side authentication policy, see OpenSSH authentication and sshd_config.

When you run ssh web, the client merges settings from the command line, your user file, and the system file. The next section lists that order and the exceptions (Include, Match, and keywords that accumulate).

Modern OpenSSH defaults already prefer strong ciphers and MACs. This article does not pin legacy CBC or 3DES lists in client config; leave algorithm policy to defaults or to server-side sshd_config when you harden hosts.


Configuration precedence and where settings come from

OpenSSH documents client precedence in ssh_config(5) in three layers. For most keywords, the highest layer that sets a value wins. Inside a single file, the first obtained value wins as matching Host and Match stanzas are read from top to bottom.

Three layers (highest priority first)

Priority Source Examples
1 Command line ssh -p 2222 web, ssh -i ~/.ssh/key, ssh -o User=admin
2 User config ~/.ssh/config
3 System config /etc/ssh/ssh_config

A Port line in ~/.ssh/config does not override ssh -p 2222. Command-line -o Keyword=value options sit in the same top layer as -p, -i, and -l.

First match inside a config file

Walk the file from the first line downward. Each Host pattern that matches the name you typed (or passed to scp / sftp) can contribute settings. For most keywords, OpenSSH keeps the first value obtained and ignores later duplicates from other matching stanzas.

Put specific hosts above broad catch-alls:

  • Host web before Host *
  • Negated patterns (!host) on the same Host line as a positive pattern that matches first

Match stanzas add another gate: declarations under Match apply only when every criterion on the Match line is true (user, host, localnetwork, exec, and others documented in ssh_config(5)). The same first-obtained rule applies inside an active Match block.

When CanonicalizeHostname is enabled, OpenSSH may evaluate Match during canonicalization and again against the final hostname. Treat Match as conditional overlays, not a separate precedence layer above the command line.

Keywords that accumulate instead of stopping at the first line

Some directives append values rather than obeying first-wins:

  • IdentityFile and CertificateFile — each line adds another key or certificate to try, in order
  • LocalForward, RemoteForward, and DynamicForward — each line adds another forward

Use IdentitiesOnly yes when you want one IdentityFile and no extra keys from agent or default paths.

Other ways settings enter the mix

Method What happens
Include ~/.ssh/config.d/*.conf Files are read at that line; globs expand in lexical order; first obtained value wins—put specific stanzas before defaults in the parent file and in each included file
Include inside Host or Match Snippet applies only when that block matches
ssh -F /path/to/alternate Replaces ~/.ssh/config; /etc/ssh/ssh_config is not read
ssh -F none Skips all configuration files
Environment in paths Include and path arguments can expand ~, tokens such as %h, and environment variables per ssh_config(5)

Relative paths in a user config file resolve under ~/.ssh/. Paths in the system file resolve under /etc/ssh/.

Verify precedence without connecting

Use the same flags you plan at login time. ssh -G prints the merged client configuration after Host, Match, and Include processing:

bash
ssh -p 2222 -G localhost

Filter the port line to confirm the command-line flag overrode config defaults:

bash
ssh -p 2222 -G localhost | grep '^port '

Sample output:

output
port 2222

port 2222 with -p 2222 on the command line shows CLI precedence even when a Host block sets a different Port.


Create ~/.ssh/config and set permissions

~/.ssh/config must not be writable by other users. Mode 600 is a simple, recommended choice. The 700 and 600 modes match the owner-only pattern for sensitive paths in Linux file permissions.

bash
mkdir -p ~/.ssh && chmod 700 ~/.ssh

chmod on an existing ~/.ssh directory exits silently when permissions are already correct.

Create an empty config file and restrict it to your user:

bash
touch ~/.ssh/config && chmod 600 ~/.ssh/config

Confirm the mode bits before you add host blocks:

bash
ls -la ~/.ssh/config

Sample output:

output
-rw-------. 1 user user 0 Aug 15 19:16 /home/user/.ssh/config

The leading -rw------- is what you want: only your account can read or write the file.


Create a host alias

A Host line defines the alias you type on the command line. HostName is the real DNS name or IP—when names fail to resolve, check Linux hostname resolution before blaming SSH. Optional User and Port replace user@ and -p on every connect.

Add a block like this to ~/.ssh/config:

text
Host web
    HostName server.example.com
    User deploy
    Port 22

After you save the file, ask OpenSSH what it would use for the alias (no network connection):

bash
ssh -G web

Sample output (trimmed):

output
host web
user deploy
hostname server.example.com
port 22

The hostname and user lines confirm the alias maps to deploy@server.example.com on port 22, so ssh web is enough at the shell.


Use a different SSH key with IdentityFile

Servers that see many keys from your account may reject the connection before you reach the right one. Point SSH at one private key and stop offering the rest with IdentitiesOnly yes. Create the matching key with ssh-keygen first; see generate SSH keys on Linux for ed25519 examples.

text
Host github.com
    HostName github.com
    User git
    IdentityFile ~/.ssh/id_ed25519_github
    IdentitiesOnly yes

Print the key SSH selected for that host:

bash
ssh -G github.com

Sample output:

output
user git
hostname github.com
identitiesonly yes
identityfile ~/.ssh/id_ed25519_github

When identityfile lists only the path you set, SSH will not offer every key in ~/.ssh/ during authentication.


Configure multiple SSH hosts

Stack independent Host sections in one file. Each block applies only when its pattern matches the name you pass to ssh.

text
Host web
    HostName web.example.com
    User deploy

Host db
    HostName db.internal.example.com
    User admin
    Port 2222

Host monitor
    HostName 10.0.0.50
    User root
    IdentityFile ~/.ssh/id_ed25519_ops

Verify one alias at a time so you can see which block matched:

bash
ssh -G db

Sample output:

output
user admin
hostname db.internal.example.com
port 2222

The port 2222 line shows this block overrode the default SSH port without putting -p on the command line.


Use wildcards and negated host patterns

Host patterns support * and ? glob characters. A leading ! excludes a host from the stanza. A negated pattern does not match anything by itself — OpenSSH requires a positive pattern on the same Host line.

text
Host *.lab.example.com
    User labadmin
    IdentityFile ~/.ssh/id_ed25519_lab

Host *.lab.example.com !bastion.lab.example.com
    ProxyJump bastion.lab.example.com

Host bastion.lab.example.com
    HostName bastion.lab.example.com
    User jump

Host *.lab.example.com !bastion.lab.example.com matches lab hosts except the bastion. The first block still applies labadmin and the lab key to every name under *.lab.example.com, including the bastion. The third block adds HostName and User jump for the bastion hostname; keywords already set by an earlier matching stanza are not replaced.

Check an internal lab host (not the bastion):

bash
ssh -G app1.lab.example.com

Sample output:

output
user labadmin
hostname app1.lab.example.com
identityfile ~/.ssh/id_ed25519_lab
proxyjump bastion.lab.example.com

proxyjump on app1.lab.example.com confirms the combined positive-and-negated pattern applied the jump rule without affecting the bastion itself.


Connect through a jump host with ProxyJump

ProxyJump (OpenSSH 7.3+) opens SSH to a bastion first, then forwards the session to the target. It replaces the older ProxyCommand nc pattern for most bastion setups.

text
Host bastion
    HostName bastion.example.com
    User jumpuser

Host internal
    HostName 10.0.0.20
    User appuser
    ProxyJump bastion

Inspect the jump setting without logging in:

bash
ssh -G internal

Sample output:

output
user appuser
hostname 10.0.0.20
proxyjump bastion

proxyjump bastion means SSH resolves the bastion Host block and chains through it before reaching 10.0.0.20. You can also write ProxyJump jumpuser@bastion.example.com when you do not need a separate alias.


Split SSH configuration with Include

Large configs stay readable when you split them. Include is processed where it appears in the file—same first-obtained rule as any other stanza. Put more-specific Host blocks before broader defaults in the parent file and inside each file under config.d/.

text
Include ~/.ssh/config.d/*.conf

Host web
    HostName web.example.com

Create a snippet file such as ~/.ssh/config.d/work.conf:

text
Host work-*
    User deploy
    Port 2222

Paths without a leading / or ~ are resolved under ~/.ssh/ when they appear in a user config file. Wildcards in the Include path expand in lexical order.

Confirm an included pattern:

bash
ssh -G work-api

Sample output:

output
user deploy
hostname work-api
port 2222

user deploy and port 2222 came from the included file. If a later stanza in the parent file tried to change User for work-api, OpenSSH would keep the first value from the included block.


Reuse connections with ControlMaster and ControlPersist

Multiplexing keeps one TCP connection open and attaches later ssh sessions to it. That cuts repeated handshakes when you run many commands to the same host.

text
Host *
    ControlMaster auto
    ControlPath ~/.ssh/cm-%C
    ControlPersist 10m

ControlPersist 10m keeps the master socket for ten minutes after the last session closes. %C hashes connection attributes into the socket name, which avoids long paths when hostnames or usernames are lengthy. OpenSSH also accepts %r, %h, and %p in ControlPath if you prefer readable socket names.

See whether the options applied to a target:

bash
ssh -G localhost

Sample output:

output
controlmaster auto
controlpath /home/user/.ssh/cm-b3edda29e4f0202401412aeb64ff97c3c2b8df60
controlpersist 600

controlpersist 600 is ten minutes in seconds. Multiplexing is convenient on trusted networks; for idle disconnects without sharing sockets, see keep alive SSH sessions (ServerAliveInterval). Disable multiplexing (ControlMaster no) when connection sharing is not acceptable for your policy.


Check the effective SSH configuration with ssh -G

When a host picks the wrong key or ignores your port, print the merged configuration instead of guessing. ssh -G hostname evaluates Host, Match, and Include processing without opening a connection.

Filter the lines you care about:

bash
ssh -G web | grep -E '^(hostname|user|port|identityfile|proxyjump|identitiesonly)'

Sample output:

output
user deploy
hostname server.example.com
port 22

Compare that to ssh -v web when you need a live handshake trace; -G is the fast check for static client keywords. It does not contact the server or prove your key is in authorized_keys on the remote side. For -v, port forwarding, and jump-host flags on the command line, see the ssh command.


Common SSH config problems

When Permission denied (publickey) persists after you set IdentityFile, the fault is often on the server key install or sshd policy—see SSH key authentication for authorized_keys, permissions, and pubkey troubleshooting.

Symptom Likely cause Fix
Alias ignored; defaults used Host * or broad wildcard listed before the specific Host Move specific blocks above catch-alls; run ssh -G alias
Config ignored entirely ssh -F /path skips /etc/ssh/ssh_config; ssh -F none skips all files Drop -F to restore defaults, or copy needed system keywords into your -F file
Wrong username or port First matching Host block already set User or Port Reorder blocks or rename the alias; first obtained value wins
-p or -i seems ignored Unlikely—CLI beats config; check you are not wrapping ssh in a script that omits flags Re-run with ssh -p … -G host; compare to ssh -G host without flags
Permission denied (publickey) with many keys SSH offers every key in ~/.ssh/ Set IdentityFile and IdentitiesOnly yes on that Host
Bad owner or permissions on ~/.ssh/config File or directory writable by group or others chmod 700 ~/.ssh and chmod 600 ~/.ssh/config
ProxyJump fails or loops Bastion alias missing or wrong HostName Define Host bastion first; verify with ssh -G internal
Include snippet ignored Wrong path or glob; relative path not under ~/.ssh/ Use Include ~/.ssh/config.d/*.conf; check glob expansion
Included value cannot be overridden First obtained value already set in an earlier stanza or included file Put specific Host blocks before defaults in every file; reorder Include
Multiplex socket errors Stale ControlPath after crash or UID change Remove ~/.ssh/cm-* sockets or set ControlMaster no for that host

References


Summary

~/.ssh/config is the OpenSSH client shortcut file. Each Host block turns a short name into HostName, User, Port, and key paths so daily ssh commands stay short. You practiced aliases, per-host keys with IdentitiesOnly, wildcards with negation, and ProxyJump for bastion access without embedding ProxyCommand shell.

Precedence runs in three layers: command line, then ~/.ssh/config, then /etc/ssh/ssh_config. Inside a file, most keywords keep the first value obtained from matching Host and Match stanzas read top to bottom; IdentityFile and port-forward directives are exceptions that accumulate. Broad Host * stanzas belong near the bottom, and split files under Include ~/.ssh/config.d/*.conf need the same specific-before-general ordering. When something looks wrong before you connect, ssh -G hostname (with the same -p, -i, or -F flags you use live) shows the merged client view faster than trial and error.

Connection multiplexing with ControlMaster and ControlPersist speeds up repeated sessions to the same machine; turn it off when shared sockets are not allowed. Server authentication policy lives in sshd_config, not in manually pinned client cipher lists. Next, copy files with the scp command using the same host aliases, or open tunnels with SSH port forwarding when config keywords are not enough.


Frequently Asked Questions

1. Where is the SSH config file on Linux?

Per-user client settings live in ~/.ssh/config. The system-wide client file is /etc/ssh/ssh_config. Server settings are separate in /etc/ssh/sshd_config.

2. Does SSH config override command-line options?

No. Command-line flags and -o options beat both config files. OpenSSH then reads ~/.ssh/config, then /etc/ssh/ssh_config. Inside each file, the first obtained value for each keyword usually wins as matching Host stanzas are walked top to bottom.

3. How do I test my SSH config without connecting?

Run ssh -G hostname to print the effective client configuration after Host, Match, and Include processing. Replace hostname with your alias or pattern match.
Omer Cakmak

Linux Administrator

Highly skilled at managing Debian, Ubuntu, CentOS, Oracle Linux, and Red Hat servers. Proficient in bash scripting, Ansible, and AWX central server management, he handles server operations on OpenStack, KVM, Proxmox, and VMware.

  • Debian
  • Ubuntu
  • Linux
  • Red Hat Enterprise Linux
  • Shell Script
  • System Administration