Skip to content
Go back

The SSH Config File: The Shortcut You're Not Using

By SumGuy 4 min read
The SSH Config File: The Shortcut You're Not Using

You type this 10 times a day:

Terminal window
ssh -i ~/.ssh/keys/prod -p 2222 admin@prod-server.example.com

Stop. There’s a better way.

Your ~/.ssh/config file can turn that into:

Terminal window
ssh prod

That’s it. One word. Everything else is configuration.

Basic Syntax

~/.ssh/config
Host prod
HostName prod-server.example.com
User admin
Port 2222
IdentityFile ~/.ssh/keys/prod

Now:

Terminal window
$ ssh prod
# Expands to: ssh -i ~/.ssh/keys/prod -p 2222 admin@prod-server.example.com

Magic. (It’s not magic. It’s just config.)

Common Options

~/.ssh/config
Host myserver
HostName actual-hostname.com
User myusername
Port 2222
IdentityFile ~/.ssh/id_ed25519
IdentityFile ~/.ssh/id_rsa_backup
# Compression (helps over slow links)
Compression yes
# Keep connection alive (no timeout)
ServerAliveInterval 60
ServerAliveCountMax 10
# Disable password auth (force key-only)
PasswordAuthentication no
# Enable agent forwarding (careful with security!)
ForwardAgent yes
# Local port forwarding
LocalForward 8080 localhost:8080
# X11 forwarding (for GUI apps)
ForwardX11 yes
# Use a specific SSH config per-host
ConfigFile ~/.ssh/configs/prod.conf

Multiple Keys Per Host

If a host accepts multiple keys, list them:

~/.ssh/config
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/github_rsa
IdentityFile ~/.ssh/github_ed25519
IdentityFile ~/.ssh/personal_key

SSH tries them in order. First one that works wins.

Wildcards (Pattern Matching)

Match groups of hosts:

~/.ssh/config
Host prod-*
User admin
Port 2222
ForwardAgent no
Host dev-*
User developer
PasswordAuthentication yes
Host *.example.com
User myuser
IdentityFile ~/.ssh/id_ed25519

Now:

Terminal window
$ ssh prod-web-01 # Uses admin, port 2222
$ ssh dev-local # Uses developer, password auth
$ ssh test.example.com # Uses myuser, ed25519 key

ProxyJump: Jump Hosts (The Best Feature)

You have a jump host (bastion) you route through:

Terminal window
# Without config:
ssh -J jumphost user@internal-server
# Or the old way (painful):
ssh user@jumphost
# Then from jumphost:
ssh user@internal-server

With config:

~/.ssh/config
Host jumphost
HostName jump.example.com
User admin
IdentityFile ~/.ssh/jump_key
Host internal
HostName internal-server.local
User appuser
IdentityFile ~/.ssh/app_key
ProxyJump jumphost

Now:

Terminal window
$ ssh internal
# SSH tunnels through jumphost automatically

Chain multiple jumps:

~/.ssh/config
Host jump1
HostName jump1.example.com
Host jump2
ProxyJump jump1
HostName jump2.internal.local
Host final
ProxyJump jump2
HostName final-server.local
Terminal window
$ ssh final
# Routes: local -> jump1 -> jump2 -> final-server

Practical Example: Multi-Environment Setup

~/.ssh/config
# Production (strict security)
Host prod-*
HostName %h.prod.internal
User deploy
IdentityFile ~/.ssh/prod_rsa
PasswordAuthentication no
ForwardAgent no
StrictHostKeyChecking accept-new
# Development (relaxed)
Host dev-*
HostName %h.dev.local
User dev
IdentityFile ~/.ssh/dev_rsa
PasswordAuthentication yes
# Bastion
Host bastion
HostName bastion.example.com
User admin
Port 2222
# Internal servers via bastion
Host *.internal
ProxyJump bastion
User appuser
IdentityFile ~/.ssh/internal_key
# Quick test server
Host test
HostName 192.168.1.100
User root
StrictHostKeyChecking no

Now you can:

Terminal window
$ ssh prod-web-01 # Direct to prod
$ ssh dev-api # Direct to dev
$ ssh internal-db-01 # Routes through bastion
$ ssh test # Local testing

Debugging: See What’s Happening

Terminal window
$ ssh -G prod
# Shows resolved config for host 'prod'

Or verbose mode:

Terminal window
$ ssh -v prod
# Shows connection details

Very verbose:

Terminal window
$ ssh -vv prod

Include Other Config Files

For teams or complex setups:

~/.ssh/config
# Global defaults
Host *
ServerAliveInterval 60
# Include team configs
Include ~/.ssh/configs/team/*.conf
Include ~/.ssh/configs/production.conf

Then manage separate files:

Terminal window
~/.ssh/configs/
production.conf
staging.conf
personal.conf

SCP and Rsync

Aliases work everywhere SSH is used:

Terminal window
# Copy file via SSH alias
$ scp myfile prod:~
# Rsync via SSH alias
$ rsync -av data/ prod:~/backup/

Gotchas

%h expands to the Host name you use. So Host prod-* with HostName %h.internal means ssh prod-web-01 becomes prod-web-01.internal.

Order matters. First matching Host block wins. Put specific hosts before wildcards:

~/.ssh/config
Host prod-db-01
# Specific config for this one
Port 3333
Host prod-*
# Generic config for all prod-*
Port 2222

StrictHostKeyChecking=accept-new is safer than =no. It accepts new hosts once, then locks them.

Permissions

Keep it readable but not world-visible:

Terminal window
chmod 600 ~/.ssh/config

If group or others can read it, SSH will ignore it for security.

Bottom Line

~/.ssh/config is your friend. Takes 5 minutes to set up, saves hours of typing. Most teams already need jump hosts and multiple environments—might as well make it painless.

ProxyJump Chains

If you need to hop through multiple bastions:

Host internal-db
HostName 10.0.1.50
User ubuntu
ProxyJump bastion1,bastion2

This chains through bastion1 then bastion2 to reach internal-db. Each jump is a separate SSH connection. The syntax works in OpenSSH 7.3+, which is anything modern.

Check your version: ssh -V.


Share this post on:

Send a Webmention

Written about this post on your own site? Send a webmention and it may appear here.


Previous Post
find Flags You Keep Forgetting
Next Post
Why the `latest` Docker Tag Is Lying to You

Related Posts