SSH keys replace passwords with a pair of files: a private key you keep and a public key the server holds. The server challenges anyone connecting to prove they hold the private key, and only the real holder can.
The practical consequence is that guessing stops working, which removes the entire category of attack that fills your logs.
Where to generate the key
cPanel offers to generate a key pair for you, and that is the option to think about before using.
A key generated on the server means the private key existed on the server and was downloaded. That is acceptable and it is not ideal. The private key should never have been anywhere but your own machine.
Generate it locally instead:
ssh-keygen -t ed25519 -C "jane@laptop"
Then paste the public key into cPanel's Import feature. Only the public half ever leaves your machine, which is the whole design.
Ed25519 keys are short, fast and current. RSA at 4096 bits is the fallback for anything that does not support Ed25519.
Importing and authorising
In cPanel, under SSH Access, choose Manage SSH Keys and import the public key. Give it a name identifying the machine it lives on, jane-laptop, not key1.
Then authorise it. This is a separate step and it is the one people miss: an imported key that has not been authorised is stored and not accepted, and the connection fails with a message about permission that gives no hint why.
Authorising writes the key into ~/.ssh/authorized_keys, which is what the server actually reads.
Connecting with it
ssh -p PORT -i ~/.ssh/id_ed25519 [email protected]
Note the port. Many hosts run SSH on a non-standard port, and the connection simply times out if you use 22 when they do not, which reads as "SSH is not enabled" rather than "wrong port".
Rather than typing the flags each time, put it in ~/.ssh/config:
Host mysite HostName example.com User username Port 2222 IdentityFile ~/.ssh/id_ed25519
Then ssh mysite is the whole command, and the same entry is used by scp, rsync and Git.
Use a passphrase
A private key without one is a plain file. Anyone who copies it (from a stolen laptop, a shared backup, a synced folder) has your server.
A passphrase encrypts the key so the file alone is useless. Use an agent so you type it once per session rather than per connection:
ssh-add ~/.ssh/id_ed25519
The common objection is that it is inconvenient. With an agent it is one prompt a day, and it is the difference between losing a laptop and losing a server.
Permissions matter and produce a confusing error
SSH refuses to use a private key that others can read, and the refusal does not say so plainly: it falls back to asking for a password, which looks like the key not working.
chmod 700 ~/.ssh chmod 600 ~/.ssh/id_ed25519
On the server side the same applies to ~/.ssh and authorized_keys. If cPanel authorised the key for you, this is already correct; if you edited the file by hand, check it. There is more on reading the numbers in understanding file permissions.
One key per machine, not per person
Generate a separate key on each computer you connect from, and authorise each on the server.
Copying one key between your laptop and your desktop feels simpler and removes your ability to revoke one. A laptop that goes missing should cost you one key, not every machine's access.
The same applies to people: each person gets their own key on their own account. A key file passed between colleagues is a shared password with extra steps. Securing your hosting account deals with the wider access question.
Keys for scripts and deployments
A deployment script or a Git integration needs its own key, generated for that purpose and named accordingly.
That key cannot have a passphrase, because nothing is there to type it. So treat it as more sensitive rather than less: restrict what it can do where possible, store it with tight permissions, and never commit it to a repository.
A deployment key in a repository is the classic route to a compromised server, and removing it later does not remove it from the history. There is more on the equivalent problem for tokens in using cPanel API tokens.
Review the authorised list
Open Manage SSH Keys occasionally and read what is there.
Keys accumulate: a contractor's key from a project two years ago, a laptop that was replaced, a deployment key for a system nobody uses. Each is a working credential nobody is watching.
Delete anything you cannot account for. If unsure, deauthorise rather than delete, see what breaks, and remove it a week later when nothing has.
When it does not work
Four causes, in the order to check them.
The key was imported but not authorised. The most common by a distance.
The wrong port, producing a timeout instead of a refusal.
Local permissions on the key file, producing a password prompt instead.
SSH not enabled on the account, which is a support question on some shared plans.
Run ssh -v and read the output. It says which keys it offered and what the server did with them, which distinguishes all four in one command. cPanel terminal and SSH access goes into what you can do once you are in.
Know which key was actually used
When several keys exist, working out which one authenticated is guesswork until you ask.
ssh -v [email protected] 2>&1 | grep -iE 'offering|will attempt|authenticated|publickey' ssh-add -l ssh-keygen -lf ~/.ssh/id_ed25519.pub
The verbose output lists each key offered and which one was accepted. The fingerprint from the last command is what appears in the server's log, which is how you match a session to a key after the fact.
This matters when removing access. Deleting the wrong entry from the authorised list either fails to revoke anything or locks out the person you meant to keep, and both are avoidable by comparing fingerprints rather than filenames.
Restrict what a key may do
A key authorises a login by default, and for automated use that is more access than the task needs.
command="/usr/local/bin/backup-only",no-pty,no-agent-forwarding,no-port-forwarding,no-X11-forwarding ssh-ed25519 AAAA... deploy@ci from="203.0.113.10",no-pty ssh-ed25519 AAAA... backup@remote
The fixed command means the key can run one thing regardless of what is requested. The address restriction means a stolen key is useless from anywhere else.
These belong on every key that exists for a script rather than a person. A deployment key with full shell access is a shell account with no password policy, no review and no expiry, held wherever the automation runs. SSH config, jump hosts and key agents covers the client side.
Rotate before you have to
Keys do not expire, so a key generated on a laptop five years ago is still authorised on servers nobody associates with that laptop.
ssh-keygen -lf ~/.ssh/authorized_keys
awk '{print $NF}' ~/.ssh/authorized_keys
The comment at the end of each line is the only record of whose key it is, which is why writing a meaningful one at creation time matters more than it appears to.
Rotate by adding the new key, confirming it works from a second session, and then removing the old one. Removing first is how people lock themselves out, and it happens most often to the person doing the tidying rather than to anyone else.