~/.ssh/config Tips: Organizing Your SSH Connection Settings

~/.ssh/config Tips: Organizing Your SSH Connection Settings

What Is ~/.ssh/config?

~/.ssh/config lets you replace a long SSH command like ssh user@192.0.2.10 -i ~/.ssh/mykey -p 2222 with a simple alias: ssh myserver. Each host block stores the hostname, user, port, and key file for that connection — making it essential when managing multiple servers.

Key Takeaways

  • Consolidate all long ssh commands into named aliases in ~/.ssh/config
  • Use ProxyJump for bastion host connections in one line
  • Place Host * at the end of the file to set global defaults

Prerequisites

Creating the File and Setting Permissions

If the file does not exist, create it and set the correct permissions:

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

600 is required. If the config file is readable by the group or others, OpenSSH ignores it entirely and prints:

Bad owner or permissions on /home/user/.ssh/config

Fix with chmod 600 ~/.ssh/config.

Basic Syntax

The file consists of Host blocks, one per alias. Options inside each block are indented (four spaces is the convention).

Host <alias>
    HostName      <IP address or FQDN>
    User          <login username>
    Port          <port number>
    IdentityFile  <path to private key>

OpenSSH evaluates blocks top-to-bottom and uses the first match. Later blocks can add values for options not yet set, but cannot override values already matched. This means specific entries must come before broad defaults.

Common Options

Option Description Example
HostName Real IP or FQDN 192.0.2.10
User Login username ubuntu
Port Port number 2222
IdentityFile Private key path ~/.ssh/id_ed25519_work
ProxyJump Jump host bastion
ServerAliveInterval KeepAlive interval (seconds) 60
ServerAliveCountMax Max unanswered keepalives before disconnect 3
Compression Enable compression yes
ForwardAgent SSH agent forwarding yes
AddKeysToAgent Auto-add key to ssh-agent yes
StrictHostKeyChecking Host key verification behavior accept-new

Managing Multiple Servers with Aliases

The most common use case: one block per server.

Host web01
    HostName 192.0.2.10
    User ubuntu
    Port 22
    IdentityFile ~/.ssh/id_ed25519

Host web02
    HostName 192.0.2.20
    User ec2-user
    IdentityFile ~/.ssh/id_ed25519_aws

Host staging
    HostName staging.example.com
    User deploy
    Port 2222
    IdentityFile ~/.ssh/id_ed25519_staging

After saving, connect with a short alias:

ssh web01
ssh staging
scp file.txt staging:/home/deploy/

scp and rsync also accept the alias — no need to repeat the full connection options.

ProxyJump: Connecting Through a Bastion Host

Production environments often restrict direct SSH access — all connections must go through a bastion host. ProxyJump handles this transparently.

Host bastion
    HostName bastion.example.com
    User ubuntu
    IdentityFile ~/.ssh/id_ed25519

Host prod01
    HostName 10.0.0.10
    User ubuntu
    ProxyJump bastion
    IdentityFile ~/.ssh/id_ed25519

Host prod02
    HostName 10.0.0.11
    User ubuntu
    ProxyJump bastion
    IdentityFile ~/.ssh/id_ed25519

Connect with a single command:

ssh prod01

SSH automatically connects to bastion first, then tunnels through to prod01.

ProxyJump requires OpenSSH 7.3 or later. Check your version with ssh -V. For older versions, use ProxyCommand ssh -W %h:%p bastion as a substitute.

Multi-hop bastions (bastion1 → bastion2 → target) can be written with a comma:

Host deep-prod
    HostName 10.1.0.5
    User ubuntu
    ProxyJump bastion1,bastion2

Using Different Keys per Host

Use separate keys for GitHub, AWS, and internal servers with wildcards:

Host github.com
    IdentityFile ~/.ssh/id_ed25519_github
    User git

Host *.company.internal
    IdentityFile ~/.ssh/id_ed25519_company
    User john

Host *.amazonaws.com
    IdentityFile ~/.ssh/id_rsa_aws
    User ec2-user

The wildcard *.company.internal applies the same key and user to all hosts in that domain — no need to list each server individually.

Global Defaults with Host *

Host * applies to every connection. Always place it at the end of the file because OpenSSH stops evaluating after the first match for each option.

# Specific entries first
Host web01
    HostName 192.0.2.10
    User ubuntu

Host bastion
    HostName bastion.example.com
    User ubuntu

# Global defaults — always at the bottom
Host *
    ServerAliveInterval 60
    ServerAliveCountMax 3
    AddKeysToAgent yes
    IdentityFile ~/.ssh/id_ed25519
  • ServerAliveInterval 60 + ServerAliveCountMax 3: disconnect after 180 seconds of inactivity. Prevents stuck sessions over unreliable networks.
  • AddKeysToAgent yes: automatically loads the key into ssh-agent on first use, so the passphrase is only entered once per login session.

Verifying Your Configuration

Use -G to print all resolved options for an alias without connecting:

ssh -G prod01

This shows every option that would apply, including inherited Host * defaults — useful for debugging unexpected behavior.

For a verbose trace during an actual connection:

ssh -v prod01 2>&1 | grep -E "identity|proxy|config"

Copy-Paste Template

Minimal working template

# Bastion host
Host bastion
    HostName bastion.example.com
    User ubuntu
    IdentityFile ~/.ssh/id_ed25519

# Production server (via bastion)
Host prod01
    HostName 10.0.0.10
    User ubuntu
    ProxyJump bastion
    IdentityFile ~/.ssh/id_ed25519

# Global defaults — must be last
Host *
    ServerAliveInterval 60
    ServerAliveCountMax 3
    AddKeysToAgent yes
    StrictHostKeyChecking accept-new

Next Reading