Article

SSH Security Guide: Keys, Root Login, and Hardening

SSH is one of the most attacked services on the internet — automated bots probe port 22 continuously, cycling through common usernames and passwords. The fix is a handful of configuration changes: disable root login, switch to SSH key authentication, avoid predictable usernames, and add Fail2ban to cut the noise.

By Paul Rudenko, Security ResearcherUpdated Jul 9, 20269 min read

SSH is how most administrators reach a remote server, and it is also one of the most aggressively attacked services on the internet — any server with port 22 open receives thousands of login attempts a day, almost none of them from a human. The good news is that SSH can be made close to impenetrable with a handful of configuration changes. This guide covers what the real risk looks like and exactly how to close it.

For the server owner (plain English)

Picture your server's front door getting rattled by strangers all day, every day — not because anyone singled you out, but because a robot walks down every street on the internet trying every door handle. That is SSH traffic on a public server: automated bots trying common usernames and passwords, nonstop, from the moment it goes online.

The fix is not a better password — it's changing what kind of key opens the door at all. Swap the password lock for a key that cannot be guessed, remove the one username every server on earth shares (root), and the knocking continues but nothing the bots try ever works.

How bad are SSH attacks, really?

From the moment a server goes online, bots begin probing port 22. These are not targeted attacks against you specifically — they are automated scripts scanning every IP address on the internet for weak credentials. The scale is real: a typical public server sees hundreds to thousands of login attempts a day, accumulating into tens of thousands of attempts from hundreds of IPs across dozens of countries within weeks.

The method is simple — a brute-force attack: cycle through lists of common usernames and passwords, trying every combination. It requires no skill or knowledge of your specific server, just time and automation. (The same technique targets web login forms; see how to defend those in the login rate-limit guide.)

Why are passwords a poor choice for SSH?

A password has a fundamental weakness: it can be guessed. No matter how strong it is, enough time and computation eventually finds it. In practice, most successful password intrusions don't even need a long brute-force campaign — they succeed because the password is common or predictable, reused from another breached service, or technically compliant but still guessable. Passwords also carry risks brute force doesn't: they can be captured by malware on a compromised device, leaked from a breached password manager, and — unlike a key tied to one device — used from anywhere by whoever has them.

SSH keys: a different approach

Key authentication replaces the password with a cryptographic key pair: a private key that never leaves your computer, and a public key placed on the server. When you connect, the server challenges your client to prove it holds the private key — the client signs the challenge, the server verifies the signature with the public key. The private key itself never crosses the network, so even a fully intercepted exchange gives an attacker nothing usable. Without the key file (or the device holding it), brute force against a modern key is mathematically infeasible.

Why is the root account such a target?

Every Linux system has a superuser named root, with unrestricted access to everything — every file, every configuration, the ability to remove the operating system itself. Its defining weakness: the name is identical on every Linux server in the world. An attacker doesn't need to guess the username, only the password, which turns a two-variable problem (username + password) into a one-variable problem. Look at SSH logs on any public server and the pattern is consistent — the overwhelming majority of attempts target root by name.

Disabling root login

The fix is to disable direct SSH login as root entirely, so even a correctly guessed root password cannot be used to log in over SSH. This is controlled by the SSH daemon's config file, /etc/ssh/sshd_config, which lives on the server itself (not your local machine) and can only be edited with root or sudo privileges — it is not something a regular user account can change, by design. Both settings below are documented in the OpenSSH sshd_config manual, the authoritative reference for the daemon's options.

Open it with a terminal editor over your existing SSH session:

sudo nano /etc/ssh/sshd_config
# or: sudo vim /etc/ssh/sshd_config

Find the PermitRootLogin line (it may be commented out with a #, or missing entirely) and set it to:

PermitRootLogin no

Save the file — in nano, Ctrl+O then Enter to write, Ctrl+X to exit — then restart the SSH service for the change to take effect:

sudo systemctl restart ssh

Administrative tasks that need root access still work after this — log in as a regular user and elevate with sudo when needed. Some distributions split this into drop-in files under /etc/ssh/sshd_config.d/ instead of the main file; if a value there overrides yours, edit or add it there — the daemon reads the main file and this directory together, and later entries win.

Which usernames should you avoid?

Because bots cycle through lists of common usernames, the account name itself matters. Names on standard attack wordlists get targeted far more heavily than an uncommon one:

root, admin, administrator, ubuntu, debian, ec2-user, centos, pi,
vagrant, deploy, git, ansible, jenkins, test, guest, user,
postgres, mysql, oracle, ftpuser, www-data, www, apache, nginx

A server with a user named ubuntu (the default on Ubuntu cloud images) receives far more targeted attempts against that specific name than one with an unpredictable name. A good username is not on that list, not obviously tied to your name/company/domain, not a common word — and still memorable enough for you to type reliably.

How do you create a secure user account?

On a new server, the setup sequence is:

1. Create a user with an unpredictable name

sudo adduser yourusername

2. Grant administrative privileges via the sudo group

sudo usermod -aG sudo yourusername

This lets the user run commands as root via sudo without being root themselves.

3. Generate a key pair — on your local machine, not the server

Run this on the computer you connect from (your laptop or desktop), never on the server itself:

ssh-keygen -t ed25519 -C "your_comment"

Accept the default file location and set a passphrase when prompted — the passphrase encrypts the private key file at rest, so a stolen laptop doesn't hand over the key on its own. This creates two files in ~/.ssh/ on your local machine:

  • id_ed25519 — the private key. This never leaves your machine and is never copied to the server, uploaded, or shared anywhere. Anyone who obtains this file can authenticate as you, so treat it like the master credential it is.
  • id_ed25519.pub — the public key. This is what gets copied to the server. It cannot be used to derive the private key, so there is no risk in it being visible — its only job is letting the server verify signatures made by your private key.

(ed25519 is the modern default — shorter keys, faster, and at least as strong as older RSA keys. If you ever need rsa for a legacy system, use at least 4096 bits: ssh-keygen -t rsa -b 4096.)

4. Install the public key on the server

The easiest path is ssh-copy-id, run from your local machine while you can still log in with a password (this is the last time you'll need to):

ssh-copy-id yourusername@yourserver

Or do it manually — logged in to the server as yourusername:

mkdir -p /home/yourusername/.ssh
chmod 700 /home/yourusername/.ssh

echo "contents-of-your-id_ed25519.pub" > /home/yourusername/.ssh/authorized_keys
chmod 600 /home/yourusername/.ssh/authorized_keys
chown -R yourusername:yourusername /home/yourusername/.ssh

Either way, only the .pub file's contents go into authorized_keys on the server — never paste the private key anywhere.

5. Verify the new account works before changing anything else

Common gotcha: open a second terminal and confirm you can log in as the new user while your original session stays open. This is the step that saves you — if something is misconfigured and you close your current session first, that second connection is what lets you fix it instead of being locked out.

6. Disable password authentication and root login

In /etc/ssh/sshd_config:

PermitRootLogin no
PasswordAuthentication no
MaxAuthTries 3

MaxAuthTries 3 caps authentication attempts per connection, slowing any automated attempt further.

7. Restart SSH

sudo systemctl restart ssh

What changes after you harden SSH?

Before these changes, an attacker has two clear paths in: the root account with a known username, or any other account where they might guess both username and password. After: root login is disabled, so even the correct root password does nothing over SSH; password authentication is off entirely, so no password works, correct or not; and an attacker now needs both the exact username and the private key file on your device. The attack surface shrinks dramatically — bots still probe port 22, and always will, but every attempt now fails immediately at the authentication stage. The connection is closed, the attempt is logged, and nothing is gained.

Do you still need Fail2ban?

Even with keys-only auth and no root login, bots keep trying — they don't know your configuration, so they keep knocking. Those attempts are harmless from a security standpoint at this point, but they add log noise and a small amount of connection overhead. Fail2ban watches the authentication log and automatically firewalls off any IP that exceeds a defined number of failed attempts within a time window. It doesn't meaningfully improve on keys-only security (password attacks already fail outright), but it cuts the noise.

How do you check your own exposure?

You can confirm a couple of these facts without touching the server's configuration files. Locally, sudo ss -tlnp shows what is actually listening and on which interface — cross-check it against what you intended to expose. The other half of the picture is the internet's view: whether port 22 is reachable from outside at all, alongside the other high-risk ports (databases, caches, admin services) that should almost never be.

A full external scan confirms whether port 22 — and the databases, caches and admin services that should never face the internet — are reachable from outside, the way an attacker's tooling sees them. It can't test your password or key config from outside (that would mean actively logging in, which this passive scanner deliberately never does); confirming exposure is the first half, the hardening steps above are the second.

Scan your server's external attack surface

SSH hardening is one piece of securing the server itself; pair it with the UFW firewall guide so port 22 (and everything else) is only reachable the way you actually intend.

What's the takeaway?

SSH security comes down to removing what attackers rely on: a known root username, a guessable or stealable password, a predictable account name, and unlimited attempts. Disable root login, switch to SSH keys only, pick an unpredictable username, and layer Fail2ban to cut the noise. None of these steps are complex, and together they push the realistic risk of unauthorized SSH access close to zero — the bots keep knocking, but there is nothing left for them to find.

Frequently asked questions

Why is disabling root SSH login important?

The root account exists with the same name on every Linux server in the world, so an attacker never has to guess it — only the password, or find another way in. That turns authentication into a one-variable problem instead of a two-variable one, which is why SSH logs on any public server show the overwhelming majority of login attempts targeting root by name. Setting PermitRootLogin no in /etc/ssh/sshd_config closes that off entirely: even a correctly guessed or leaked root password can no longer be used to log in over SSH. Administrative work that needs root access still happens normally — you log in as a named, non-root user and elevate privileges with sudo when a specific command requires it, so nothing about day-to-day server administration is lost.

Are SSH keys really more secure than passwords?

Yes, substantially. A password is a single secret that can be guessed through brute force, captured by malware on a compromised device, or leaked when a password manager or another service is breached — and once an attacker has it, it works from anywhere. SSH key authentication instead uses a cryptographic key pair: the private key never leaves your device, and authentication happens by signing a challenge with it, which the server verifies against the stored public key. The private key itself is never transmitted, so even fully intercepting the exchange gives an attacker nothing they can reuse, and brute-forcing a modern key is computationally infeasible. The trade-off is that a key is tied to a device or key file rather than something you can type from memory, which is exactly the property that makes it stronger.

What should I name my SSH user account?

Avoid names that appear on the wordlists automated attack tools cycle through: root, admin, administrator, common cloud-image defaults (ubuntu, debian, ec2-user, centos, pi), and common service or role names (deploy, git, jenkins, test, guest, user, www-data, postgres, and similar). A server using one of these predictable names receives measurably more targeted login attempts against that specific username than one that doesn't. A reasonable choice is a name that isn't on any common list, isn't obviously derived from your name, company, or domain, and isn't a dictionary word in any language — while still being something you can type reliably yourself. This is a minor layer compared to disabling passwords and root login, but it costs nothing, it measurably reduces the noise an unpredictable name draws, and it removes one of the two variables an attacker would otherwise get for free.

Do I still need Fail2ban if I only allow SSH keys?

Fail2ban is not what makes keys-only SSH secure — that security comes from disabling password authentication itself, which makes brute-force login attempts fail unconditionally regardless of how many bots try. What Fail2ban adds on top is practical: it watches the authentication log and automatically firewalls off any IP address that racks up repeated failed attempts within a time window, which cuts down the log noise and the small connection overhead of bots that keep probing a server they can never actually get into. It's a genuinely useful piece of housekeeping and a good defence-in-depth habit, but if you had to prioritize, disabling root login and password authentication does the actual security work; Fail2ban mostly makes the aftermath quieter. If you run it, tune the ban time and retry threshold to your own login patterns so a mistyped password on your side doesn't lock you out along with the bots.

Related guides

See your whole external attack surface

One page is a start. The full external scan covers TLS, headers, DNS, exposed files, open services and known-exploited CVEs across your whole domain.

See the full scan →