Skip to content
DevOps devops networking 5 min read

The SSH Config File

If you connect to servers a lot, you quickly get tired of typing long commands like ssh -i ~/.ssh/work_key -p 2222 [email protected]. The SSH config file fixes this. It is a plain text file where you save a short nickname (called an alias) for each server, along with all its connection settings. After that you just type ssh myserver and SSH fills in the rest. This is one of the biggest quality-of-life wins in DevOps, and it costs you five minutes to set up.

SSH (Secure Shell) is the standard tool for logging into a remote Linux machine over an encrypted connection. The config file we are talking about lives in your home directory, not on the server. It controls how your computer (the client) behaves when you run the ssh command.

Where the file lives

On Ubuntu (and macOS, and any Linux), the per-user SSH config file is at ~/.ssh/config. The ~ is shorthand for your home directory, so the full path is usually /home/yourname/.ssh/config.

The file does not exist by default. You create it yourself:

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

The chmod 600 is important. It means “only the owner can read and write this file.” SSH refuses to use a config file that other users on the machine can read or edit, because that would be a security hole.

Security tip: Never put passwords in ~/.ssh/config. The file is plain text. Use SSH keys instead (see the SSH key authentication page). The config file points to your key with IdentityFile; it never contains the secret itself.

A single-host example

Open the file in any editor:

nano ~/.ssh/config

Add a block like this:

Host webserver
    HostName 203.0.113.40
    User deploy
    Port 22
    IdentityFile ~/.ssh/id_ed25519

Save and exit. Now instead of the long command, you simply run:

ssh webserver

SSH reads the block, sees that webserver maps to the real address 203.0.113.40, logs in as the deploy user on port 22, and uses the key file you specified. That is the whole idea.

What each option means

OptionWhat it doesExample value
HostThe alias (nickname) you type after ssh.webserver
HostNameThe real IP address or domain name of the server.203.0.113.40 or web.example.com
UserThe Linux username to log in as.deploy
PortThe TCP port SSH listens on (22 is the default).22 or 2222
IdentityFilePath to the private key used to authenticate.~/.ssh/id_ed25519

Indentation under Host is just for readability; SSH does not require it. Lines starting with # are comments and are ignored.

A multi-host example

The real power shows up when you manage several servers. You list one Host block per machine:

# Production web server
Host prod
    HostName 203.0.113.40
    User deploy
    Port 22
    IdentityFile ~/.ssh/prod_ed25519

# Staging server (custom SSH port)
Host staging
    HostName staging.example.com
    User ubuntu
    Port 2222
    IdentityFile ~/.ssh/staging_ed25519

# A database box you reach with a different key
Host db
    HostName 10.0.0.15
    User postgres
    IdentityFile ~/.ssh/db_ed25519

# Settings applied to every host (must go last)
Host *
    ServerAliveInterval 60
    ServerAliveCountMax 3

Now ssh prod, ssh staging, and ssh db each connect to the right machine with the right key, user, and port. No flags to remember.

The Host * block at the bottom uses a wildcard (* means “match everything”). The two ServerAlive settings tell your client to send a tiny keep-alive packet every 60 seconds so the connection does not drop while you step away from the keyboard.

Gotcha: SSH applies the first matching value for each option, reading top to bottom. Always put specific hosts first and the catch-all Host * block last, or your general settings will shadow the specific ones.

Jump hosts with ProxyJump

Many production servers are not reachable directly from the internet. They sit on a private network (an internal-only network with no public address). To reach them you first connect to a bastion or jump host (a single hardened server that is exposed to the internet on purpose and acts as a controlled gateway). You hop through it to get to the real target.

Doing this by hand is awkward. The ProxyJump option automates the hop:

# The public gateway
Host bastion
    HostName bastion.example.com
    User ubuntu
    IdentityFile ~/.ssh/bastion_ed25519

# A private box reachable only through the bastion
Host internal-app
    HostName 10.0.1.20
    User deploy
    IdentityFile ~/.ssh/app_ed25519
    ProxyJump bastion

Now this single command transparently logs into the bastion and then forwards you to the private 10.0.1.20 box:

ssh internal-app

Output:

Welcome to Ubuntu 24.04.1 LTS (GNU/Linux 6.8.0-45-generic x86_64)
Last login: Mon Jun 15 09:12:41 2026 from 10.0.0.5
deploy@internal-app:~$

You can even chain jumps with commas, e.g. ProxyJump bastion,inner-gateway. The same alias works for scp and rsync too, so file transfers also flow through the bastion automatically.

When to use this: any time your real servers live behind a bastion, a VPN entry point, or in a private subnet. When NOT to: if your target has a direct public IP you can reach, a plain Host block is simpler.

Testing your config

To see exactly what settings SSH will use for an alias without actually connecting, run:

ssh -G prod

Output:

host 203.0.113.40
user deploy
port 22
identityfile ~/.ssh/prod_ed25519
serveraliveinterval 60
serveralivecountmax 3

This is the fastest way to debug a typo or a wrong key path.

Best practices

  • Keep ~/.ssh/config at permission 600 and the ~/.ssh directory at 700, or SSH may refuse to use them.
  • Use one private key per environment (prod, staging, db) so a single leaked key has limited blast radius.
  • Prefer modern Ed25519 keys (ssh-keygen -t ed25519) over older RSA keys.
  • Put specific Host blocks first and the Host * catch-all last so order-of-precedence works in your favour.
  • Add a comment line above each block describing what the server is for; future-you will thank you.
  • Never store passwords in the file; rely on key-based authentication only.
  • Use ProxyJump instead of saving raw ssh -W commands so file transfer tools inherit the same path.
Last updated June 15, 2026
Was this helpful?