SSH Server Hardening: From Passwords to Key-Based Auth + Fail2Ban

Published: 2026-06-11

Overview

After setting up your droplet and getting key-based login working, don't stop there. Leaving password authentication and root login enabled is the equivalent of locking your front door but leaving the windows open.

This guide covers the essential hardening steps to apply after you confirm your SSH key works, before logging out of your existing session.


Step 1: Verify Key-Based Login Works

Before touching anything, confirm you can log in with your key in a new terminal window:

ssh tony@your-domain-or-ip

If this succeeds without asking for a password, you're good. If it asks for a password, stop here — your key isn't set up correctly yet.


Step 2: Hardening sshd_config

sudo nano /etc/ssh/sshd_config

Disable password authentication — the single most important step. If a password isn't accepted, brute-force attacks become useless.

# Find and change these lines:
PasswordAuthentication no
PermitRootLogin no

Why disable root login? Attackers know root exists on every Linux system. Even with a strong password, it's a predictable target. Use sudo from your regular user account instead.

Restart the SSH daemon to apply changes:

sudo systemctl restart sshd

Step 3: Install and Configure Fail2Ban

Fail2Ban automatically blocks IPs that fail too many login attempts. Zero configuration required — the defaults work well out of the box.

# Update package lists and install
sudo apt update && sudo apt install fail2ban -y

# Enable and start the service
sudo systemctl enable fail2ban
sudo systemctl start fail2ban

# Verify it's running
sudo systemctl status fail2ban

What it does by default:

Tip: You can check current bans with: sudo fail2ban-client status sshd


Step 4: Configure the Firewall (UFW)

If ufw (Uncomplicated Firewall) is available, enable it:

# Allow SSH through the firewall (if using default port 22)
sudo ufw allow ssh

# Enable UFW (will ask for confirmation)
sudo ufw enable

# Check status
sudo ufw status verbose

Warning: If you're connecting via SSH and haven't allowed it first, ufw enable will lock you out. The command above allows SSH first, which is safe.


Step 5: Change the SSH Port (Optional but Recommended)

Port 22 is constantly scanned by bots and attackers. Changing it to something random like 2222 or 49152 drastically reduces automated attack traffic.

sudo nano /etc/ssh/sshd_config

Find the line #Port 22, uncomment it, and change the number:

Port 2222

Choose a port in the range 49152-65535 for unprivileged ports (less likely to conflict with other services). Avoid ports below 1024 unless you have a specific reason — those require root and are reserved for well-known services.

Restart SSH daemon:

sudo systemctl restart sshd

Update UFW if enabled:

# Remove the old rule (ufw allow ssh opens port 22/tcp specifically, not your new port)
sudo ufw delete allow ssh

# Open the new SSH port
sudo ufw allow 2222/tcp

# Verify
sudo ufw status verbose

Important: ufw allow ssh always resolves to port 22 via /etc/services — it does not auto-detect whatever port sshd is actually listening on. You must explicitly allow the new port number.

Test the new port before closing your session:

# In a new terminal — verify new port works
ssh -p 2222 tony@your-domain-or-ip

If it works, your old session is still alive as a fallback. Once the new port is confirmed working, the old session can be closed.


Step 6: Verify Everything Works (Critical)

Open a second terminal — do not close your current session yet.

In the new terminal, test each of these:

# 1. Can you still SSH in with your key?
ssh -p 2222 tony@your-domain-or-ip

# 2. Is password authentication rejected?
# (Try connecting from a friend's machine or phone to be sure)

# 3. Can you reach your server?
ping your-domain-or-ip

If anything fails, go back to your original session — it's still alive, so you can fix sshd_config and try again.


Quick Reference

Action Command
SSH with custom port ssh -p 2222 tony@your-domain-or-ip
Restart SSH after config change sudo systemctl restart sshd
Check SSH config syntax sudo sshd -t
View active SSH connections who
Check fail2ban status sudo fail2ban-client status sshd
Unban a specific IP sudo fail2ban-client set sshd unbanip <IP>
View UFW rules sudo ufw status verbose
Disable UFW (emergency) sudo ufw disable

Summary Checklist


What's Next


Client-Side: Windows (PuTTY / WinSCP)

If you connect from Windows, you'll need to convert your private key to PuTTY's format (.ppk) since OpenSSH keys and PuTTY don't natively understand each other.

Option 1: PuTTYgen (Convert .pem to .ppk)

  1. Download PuTTYgen if you don't have it
  2. Open PuTTYgen — click Load — select your droplet private key file
  3. PuTTY will prompt you to enter your passphrase (if set) — click OK
  4. Go to File — Save Private Key — save as droplet.ppk
  5. Never save the key without a passphrase if you can avoid it

Option 2: WinSCP (Import .pem Directly)

WinSCP can import OpenSSH keys directly without conversion:

  1. Open WinSCP — Login dialog
  2. Click Tools — Run PuTTYgen (or open PuTTYgen manually)
  3. Load your droplet private key
  4. Save as .ppk file
  5. Back in WinSCP: select the .ppk file in SSH — Authentication settings
  6. Login as tony@your-domain-or-ip

Connecting with PuTTY (Custom Port)

  1. Open PuTTY
  2. Session: Host Name = tony@your-domain-or-ip, Port = 2222 (your custom port), Connection type = SSH
  3. Connection — SSH — Auth — Private key file: browse to droplet.ppk
  4. Connection — Data: Auto-login username = tony
  5. Go back to Session, enter a name under Saved Sessions, click Save
  6. Click Open to connect

Tip: First time connecting, you'll see a host key fingerprint prompt — click Yes to cache it. This verifies you're connecting to the right server.


Client-Side: macOS / Linux (ssh-agent)

On macOS or Linux, use the OpenSSH agent to cache your passphrase so you don't type it every time.

Add Key to Agent

# Start the SSH agent (macOS may already have it running)
eval "$(ssh-agent -s)"

# Add your private key (will ask for passphrase)
ssh-add ~/.ssh/droplet

Verify Key Is Loaded

ssh-add -l

You should see your key's fingerprint. If it says The agent has no identities, the key wasn't added.

Persist Across Reboots

macOS — add to Keychain:

ssh-add --apple-use-keychain ~/.ssh/droplet

Then add this to ~/.ssh/config:

Host *
    AddKeysToAgent yes
    UseKeychain yes
    IdentityFile ~/.ssh/droplet

Linux — most desktop environments auto-start ssh-agent. You can also add to ~/.bashrc:

eval "$(ssh-agent -s)"
ssh-add ~/.ssh/droplet 2>/dev/null

~/.ssh/config for Custom Port

If you changed your SSH port, store it in your config so you don't type -p 2222 every time:

Host my-droplet
    HostName your-domain-or-ip
    Port 2222
    User tony
    IdentityFile ~/.ssh/droplet

Then just run ssh my-droplet — the config handles everything.

Copy Public Key from Linux/macOS Client

On your local machine (not the server):

# Display your public key
cat ~/.ssh/droplet.pub

# Copy to clipboard (macOS)
cat ~/.ssh/droplet.pub | pbcopy

Then paste it into the server's ~/.ssh/authorized_keys file as described in Section 4 of the original guide.


Troubleshooting

Symptom Likely Cause Fix
Permission denied (publickey) Key not in authorized_keys cat ~/.ssh/droplet.pub on client, paste into server's ~/.ssh/authorized_keys
Connection refused SSH service not running sudo systemctl start sshd
Connection timed out Firewall blocking port sudo ufw allow 2222/tcp
WARNING: UNPROTECTED PRIVATE KEY FILE Wrong file permissions chmod 600 ~/.ssh/droplet
PuTTY: No supported authentication methods available Server disabled password auth but key not configured Re-enable password auth temporarily, add key, disable again
Agent admitted failure to sign using the key Key not in ssh-agent ssh-add ~/.ssh/droplet
Can't connect after port change Forgot to specify new port ssh -p 2222 tony@your-domain-or-ip