linux

Passwordless SSH: The First Thing You Should Actually Secure

Here is an uncomfortable fact: right now, somewhere on the internet, a bot is trying “admin/admin123” against your server’s SSH port. It does not know or care that it is your server specifically, it is just working through a list. If password auth is still on, you are relying entirely on your password being strong enough to survive that, forever, without a single slip. SSH keys remove the guessing game completely, and they take about five minutes to set up.

Step 1: Generate a key pair

On your local machine, not the server:

ssh-keygen -t ed25519 -C "your_email@example.com"

Hit enter through the prompts (a passphrase is optional but recommended, it protects the key itself if your laptop ever gets stolen). This creates two files: a private key that never leaves your machine, and a public key that is safe to hand out.

Step 2: Copy the public key to your server

ssh-copy-id user@your-server-ip

This drops your public key into the right place on the server (~/.ssh/authorized_keys) automatically. No ssh-copy-id available on your system? Just paste the contents of your .pub file into that file manually. Same result, one extra step.

Step 3: Confirm key login works

Open a new terminal window (do not close your current session yet) and try logging in again. You should get straight in with no password prompt at all.

ssh user@your-server-ip

If that worked, keep that first session open just in case, and move to the last step.

Step 4: Actually disable password login

This is the step that actually matters. Having a key is nice; it changes nothing on its own if password login is still allowed. Edit the SSH config on the server:

sudo nano /etc/ssh/sshd_config

Find (or add) these two lines and make sure they read exactly this:

PasswordAuthentication no
PubkeyAuthentication yes

Save, then restart the SSH service:

sudo systemctl restart sshd

Do not close that first terminal session until you have confirmed a fresh login still works. If you lock yourself out, that spare open session is the only way back in without physical or console access.

That’s it

No more password to brute-force, no more “was that P@ssw0rd1 or P@ssw0rd2” guessing games. Every automated bot hammering your SSH port is now wasting its time against an authentication method it cannot even attempt. Five minutes of setup for one less thing to worry about. Worth it every time.

If you get “Permission denied (publickey)”

This is the error that shows up the moment PasswordAuthentication is off and something about the key setup wasn’t quite right. Work through these in order:

  • Check permissions on the server: ~/.ssh must be 700 and ~/.ssh/authorized_keys must be 600. SSH silently refuses to use a key file with looser permissions than that, without a clear error message telling you why.
  • Confirm you’re connecting as the right user, the key was added to that user’s authorized_keys, not root’s, unless you specifically copied it there too.
  • Run the connection with ssh -v user@server-ip to see verbose output, it will tell you exactly which key it tried and why the server rejected it.
  • Double check the public key on the server matches the private key on your machine, a stray extra keypair from an earlier attempt is a common cause of this.

Two more steps worth taking while you’re in sshd_config

Disabling password auth is the big one, but since you’re already editing this file:

PermitRootLogin no
MaxAuthTries 3

PermitRootLogin no stops anyone from logging in directly as root, even with a valid key, forcing a login as a regular user and then sudo if needed, which also gives you an audit trail. MaxAuthTries 3 drops the connection after a handful of failed attempts instead of letting a script hammer away indefinitely. Neither is as impactful as disabling passwords, but both are free hardening for zero extra effort.

If you want to go one step further, installing fail2ban will automatically ban IPs that fail authentication repeatedly, which matters less once passwords are off but still helps against connection-flooding.

Related reading

Similar Posts