Ahosting Logo
Knowledge Base

How to Use SSH Config, Jump Hosts and Key Agents

What a config file replacesWithout one· a long command carrying user, port, key path and jump host· pasted from a note· and different on every machine you useWith one· a short name per host· jump hosts handled automatically· and the same names for everybody who shares the fileThe agent, separatelyIt keeps a decrypted key in memory so a passphrase is typed once per session rather than onceper connection, which is what makes passphrases tolerable.

Most people connect to servers by pasting a long command from a note. A configuration file replaces all of it, and it is the difference between administering three servers and administering thirty.

The file

~/.ssh/config:

Host web1
 HostName 203.0.113.10
 User root
 Port 19070
 IdentityFile ~/.ssh/id_ed25519

Host db1
 HostName 10.0.0.5
 User admin
 ProxyJump web1

Now ssh web1 connects with the right user, port and key. And ssh db1 reaches a machine that has no public address at all, by routing through the first one.

scp and rsync read the same file, so those become short too:

scp backup.tar.gz web1:/root/
rsync -avz ./site/ web1:/var/www/site/

Using rsync for transfers and backups deals with the transfer side, and this removes the awkward -e "ssh -p ..." argument entirely.

Jump hosts

ProxyJump is the important one for any sensible network layout, where database and application servers have no public address and are reached through one bastion.

Expressed in the config, that route is a property of the destination rather than something to remember. Chains work too:

Host internal
 HostName 10.0.1.20
 ProxyJump bastion,web1

The traffic is encrypted end to end. The jump host forwards the connection without being able to read it, which is why this is better than connecting to the bastion and running SSH from there.

Defaults and patterns

Host *.example.com
 User admin
 Port 19070

Host *
 ServerAliveInterval 60
 ServerAliveCountMax 3

Patterns save repetition. ServerAliveInterval is worth setting globally: it stops idle sessions being dropped by network equipment, which is the cause of connections that freeze rather than disconnect cleanly.

The first matching value wins, so specific hosts go above the general patterns.

The agent

A passphrase-protected key is correct and asking for the passphrase on every connection is not workable.

The agent holds the decrypted key in memory:

eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
ssh-add -l

One passphrase per session. On macOS the agent is running already and the passphrase can be stored in the keychain; on Linux the desktop usually starts one.

Agent forwarding, carefully

Host web1
 ForwardAgent yes

This lets you connect onward from the remote machine using your local keys, without copying any key there. Useful for pulling from a repository on the server.

The caveat: while you are connected, root on that machine can use your agent to authenticate anywhere your keys work. That is fine on a server you control and not fine on a shared or untrusted one.

Enable it per host, never in the global block. ProxyJump is the better answer whenever the goal is simply to reach a further machine, because it forwards nothing.

One key or several

One key per person, per machine they use, is the workable arrangement: a laptop key and a desktop key, each authorised on the servers.

Then losing a laptop means removing one key rather than reissuing everything. There is more on authorising them on the server side in managing SSH keys in cPanel.

Prefer Ed25519 keys for new ones. They are shorter, fast, and supported everywhere current.

Permissions

chmod 700 ~/.ssh
chmod 600 ~/.ssh/config ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub

SSH refuses to use files it considers too permissive, and the error mentions permissions instead of the key. It is the first thing to check when a key that should work does not.

When a connection fails

ssh -vvv web1 2>&1 | head -40

The verbose output shows which config entries were applied, which keys were offered and what the server said, which usually names the problem directly. Connecting to your VPS via SSH explains the basics underneath all of this.

Reuse one connection instead of opening many

Every new session repeats the handshake and the authentication, which is why a script running twenty short commands feels slow for no obvious reason.

Host *
    ControlMaster auto
    ControlPath ~/.ssh/cm-%r@%h:%p
    ControlPersist 10m

The first connection to a host stays open in the background and later ones reuse it, so they open instantly. File copies to the same host benefit as much as shell sessions.

Two cautions. The socket path must be in a directory only you can read, since anyone who can open it inherits the session. And closing the first terminal does not close the shared connection, so ssh -O exit host is worth knowing when you want it gone.

Sessions that drop, and work that survives them

An idle session cut by a firewall or a router is the common annoyance, and half of it is fixed in the config.

Host *
    ServerAliveInterval 30
    ServerAliveCountMax 4
    TCPKeepAlive no

That sends a small message every thirty seconds and gives up after four unanswered, which keeps ordinary sessions alive through equipment that discards quiet connections.

It does not protect long-running work. A migration, a large import or a package upgrade should run inside tmux or screen so that losing the connection loses the view rather than the job. Starting the session first costs three seconds and saves the entire run.

Offer one key, not all of them

An agent holding several keys offers each in turn, and a server that allows a limited number of attempts refuses you before the right one is tried.

Host prod
    HostName 203.0.113.10
    User deploy
    IdentityFile ~/.ssh/id_prod
    IdentitiesOnly yes
    PasswordAuthentication no

IdentitiesOnly is the setting that matters. Without it the named file is added to the list rather than replacing it, and the "too many authentication failures" refusal keeps happening on a configuration that looks correct.

Turning off password authentication per host also removes a subtle risk: a prompt you did not expect is a sign something is wrong, and typing a password into it is how credentials reach the wrong machine. Managing SSH keys in cPanel goes into where the key on the other side lives.

What a changed host key means

The warning about a changed identification is the one people click past, and it is the only warning the protocol gives you.

ssh-keygen -F server.example.com
ssh-keygen -R server.example.com
ssh-keyscan -t ed25519 server.example.com

There are three ordinary explanations: the server was rebuilt, it was migrated, or the address now belongs to a different machine. There is one that is not ordinary, and nothing on your side can tell them apart.

So verify out of band. Ask for the fingerprint through the provider's panel or a colleague, compare it, and only then remove the old entry. Deleting the line first and confirming later is the habit that makes the protection decorative.