I wrote a post back in 2017 about updating SSH to version 7.5p1. Seven years and countless servers later, SSH is still the tool I use more than anything else — and I've learned a lot of tricks that save me time every single day. Most of them come down to one file: ~/.ssh/config.

Here's the SSH configuration I actually use in production, and why each piece matters.

Dark terminal screen with code
Most of my workday happens over SSH. A good config file makes it frictionless.

The Config File That Pays for Itself

Here's my ~/.ssh/config — I'll break down each section:

# Keep connections alive — no more "broken pipe"
Host *
    ServerAliveInterval 60
    ServerAliveCountMax 3
    TCPKeepAlive yes

# Connection multiplexing — one TCP connection, many sessions
Host *
    ControlMaster auto
    ControlPath ~/.ssh/sockets/%C
    ControlPersist 600

# My servers
Host production
    HostName davideandreazzini.co.uk
    User deploy
    Port 22
    IdentityFile ~/.ssh/prod_ed25519

Host staging
    HostName staging.davideandreazzini.co.uk
    User deploy
    Port 2222
    IdentityFile ~/.ssh/staging_ed25519

Host db-backup
    HostName 10.0.1.50
    User backup
    IdentityFile ~/.ssh/backup_key
    ProxyJump production

# Jump host for internal network
Host 10.0.1.*
    ProxyJump production
    User admin

# Quick local VMs
Host dev-*
    User vagrant
    IdentityFile ~/.ssh/vagrant_key
    StrictHostKeyChecking no
    UserKnownHostsFile /dev/null

This single file replaces hundreds of command-line flags and makes SSH feel like it just works. Let me walk through each piece.

Connection Keepalive: Never Lose a Session Again

If you've ever left an SSH session idle for 10 minutes and come back to a frozen terminal that you can't even Ctrl-C out of, you need ServerAliveInterval:

ServerAliveInterval 60
ServerAliveCountMax 3

This sends an encrypted keepalive probe every 60 seconds through the SSH channel. If 3 consecutive probes go unanswered (180 seconds total), the connection is terminated cleanly. The important detail: these are encrypted-channel keepalives, not TCP-level ones. They can't be spoofed by a man-in-the-middle — unlike TCPKeepAlive, which operates at the network layer.

Before I added this, I'd regularly lose sessions to my VPS in Montevideo because the connection would silently drop and my terminal would hang indefinitely. Now, dead connections close within 3 minutes and I can reconnect immediately.

Connection Multiplexing: One Connection to Rule Them All

This is the single biggest quality-of-life improvement in my SSH setup:

ControlMaster auto
ControlPath ~/.ssh/sockets/%C
ControlPersist 600

Here's what this does: the first time I ssh production, SSH establishes a TCP connection, authenticates, and creates a Unix domain socket at ~/.ssh/sockets/%C (where %C is a hash of the connection parameters). Every subsequent ssh production command connects through that existing socket — no new TCP handshake, no authentication, instant.

The practical difference:

# Without multiplexing: each connection takes 1-3 seconds
$ time ssh production "hostname"
prod-server-01
0m1.84s real

# With multiplexing: subsequent connections are instant
$ time ssh production "hostname"
prod-server-01
0m0.03s real

That's a 60x speedup. When you're running commands on remote servers dozens of times a day, this adds up. And ControlPersist 600 keeps the master connection alive for 10 minutes after the last session closes, so I can SSH in, run a command, disconnect, and reconnect instantly within that window.

One setup note: you need to create the sockets directory:

mkdir -p ~/.ssh/sockets

To manage multiplexed connections, SSH provides handy control commands:

# Check if a master connection is active
ssh -O check production

# Close the master connection (and all sessions using it)
ssh -O exit production

# Forward a port through an existing connection (no new handshake)
ssh -O forward production
Developer coding on a dark theme screen
Multiplexing means the second SSH connection to the same host is always instant.

Host Aliases: Stop Typing Long Commands

Before my config file, connecting to production looked like this:

ssh -i ~/.ssh/prod_ed25519 -p 22 deploy@davideandreazzini.co.uk

Now it's just:

ssh production

The Host directive makes it a named alias. HostName is the actual server, User and Port are self-explanatory, and IdentityFile points to the specific key. Each of my servers gets its own identity file — I never use the same key for two different services.

ProxyJump: The Gateway Pattern

My database backup server doesn't have a public IP — it's only reachable through the production server. Before I knew about ProxyJump, I'd do this:

# Old way: two manual hops
ssh -L 5432:10.0.1.50:5432 production
# Then connect to the forwarded port...

With ProxyJump, it's one command:

ssh db-backup

SSH automatically tunnels through production to reach 10.0.1.50. The ProxyJump directive in the config handles it transparently. And with multiplexing, the jump connection reuses the existing socket to production — so even multi-hop SSH is instant.

The wildcard pattern Host 10.0.1.* means any IP in that subnet automatically routes through the jump host. I never have to remember which servers are internal — SSH figures it out.

Ed25519 Keys: Smaller, Faster, More Secure

OpenSSH 9.5 generates Ed25519 keys by default, and for good reason:

# Generate a new Ed25519 key (the modern default)
ssh-keygen -t ed25519 -C "davide@production" -f ~/.ssh/prod_ed25519

# Compare key sizes
$ wc -c ~/.ssh/prod_ed25519.pub
    82 ~/.ssh/prod_ed25519.pub

$ wc -c ~/.ssh/old_rsa_4096.pub
   726 ~/.ssh/old_rsa_4096.pub

Ed25519 keys are roughly 9x shorter than 4096-bit RSA keys, faster to verify, and based on elliptic curve cryptography that's resistant to known quantum computing attacks. There's no reason to use RSA keys for new deployments anymore.

I still have a few RSA keys for older servers that don't support Ed25519, but they're the exception. If you're generating a new key today, ssh-keygen -t ed25519 is the way to go.

Keystroke Timing Obfuscation (OpenSSH 9.5+)

This is a newer feature I've started using after the CVE incident on this very blog. OpenSSH 9.5 introduced ObscureKeystrokeTiming, which hides your typing patterns from network observers:

Host *
    ObscureKeystrokeTiming yes

When enabled, SSH sends interactive traffic at fixed intervals (default: every 20ms) and injects fake keystroke chaff. This makes it significantly harder for anyone monitoring the encrypted SSH stream to infer what you're typing — which matters more than you'd think. Researchers have shown that keystroke timing analysis can reveal passwords and commands with surprising accuracy, even through an encrypted channel.

Given that someone already extracted my Ghost admin key from this server, I'll take every layer of protection I can get.

Quick Reference: My Most-Used SSH Flags

A few flags I use daily that aren't in my config file:

# Copy a file to a remote host (uses config aliases!)
scp backup.sh production:/opt/scripts/

# Or with rsync for large/synced transfers
rsync -avz --progress ./project/ production:/var/www/

# Forward a local port to a remote service
ssh -L 8080:localhost:80 production

# Forward a remote port to local (reverse tunnel)
ssh -R 9090:localhost:3000 production

# Execute a command without opening a shell
ssh production "df -h && free -m"

# Mount a remote directory locally with sshfs
sshfs production:/var/log /mnt/prod-logs

All of these work with the config aliases. scp, rsync, and sshfs all read ~/.ssh/config, so once your aliases are set up, they work everywhere.

One File, Massive Impact

The entire configuration lives in one file. It's version-controlled in my dotfiles repo. When I set up a new machine, I clone the repo, and every SSH connection works exactly the same way — same aliases, same keys, same keepalive settings, same multiplexing.

If you're still typing ssh -i key.pem -p 2222 user@some-ip every time you connect to a server, spend 10 minutes writing your ~/.ssh/config. It'll pay for itself by the end of the day. And if you're already using it, add ControlMaster auto and ControlPersist 600 — that one change will make you wonder how you ever lived without it.