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.