Skip to content

Harden SSH and Disable Root Login: A 10-Minute Server Lockdown

Step-by-step guide to harden OpenSSH, disable root login, set up key-based auth, and configure fail2ban before you host a single customer.

Written by AISali·August 4, 2026·4 min read
Harden SSH and Disable Root Login: A 10-Minute Server Lockdown

Every week, hosting resellers spin up a fresh VPS, install a control panel, and start provisioning customer accounts—all before locking down SSH. That's a critical mistake. A compromised root shell means every cPanel account, every database, every WordPress install on that box is gone.

This guide walks you through the exact SSH hardening steps you should run on every new server before it touches production traffic. Ten minutes, one reboot, and your attack surface drops dramatically.

Prerequisites#

You'll need:

  • A fresh Linux server (Ubuntu 22.04/24.04, AlmaLinux 9, or Debian 12)
  • Root or sudo access via SSH (password-based is fine for now—we're about to fix that)
  • A local machine with ssh-keygen available (macOS, Linux, or Windows with OpenSSH)

Step 1: Generate an Ed25519 Key Pair on Your Local Machine#

Ed25519 keys are shorter, faster, and more secure than RSA-4096. On your local machine:

bash
ssh-keygen -t ed25519 -C "[email protected]" -f ~/.ssh/id_ed25519_servername

Set a strong passphrase when prompted. The private key (id_ed25519_servername) never leaves your machine. The public key (id_ed25519_servername.pub) goes on the server.

Step 2: Create a Non-Root Admin User#

SSH into your server as root, then:

bash
adduser deploy
usermod -aG sudo deploy

On RHEL/AlmaLinux, replace sudo with wheel. Now copy your public key to the new user:

bash
mkdir -p /home/deploy/.ssh
cat >> /home/deploy/.ssh/authorized_keys < ~/.ssh/id_ed25519_servername.pub
chmod 700 /home/deploy/.ssh
chmod 600 /home/deploy/.ssh/authorized_keys
chown -R deploy:deploy /home/deploy/.ssh

Test it—open a new terminal and verify you can log in as deploy with your key:

bash
ssh -i ~/.ssh/id_ed25519_servername [email protected]

If that works, you're ready to harden the daemon. Do not close your existing root session yet.

Step 3: Harden the SSH Daemon Configuration#

Back up the current config, then edit it:

bash
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
nano /etc/ssh/sshd_config

Set or uncomment these directives (remove duplicates if needed):

code
Port 22
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
AuthenticationMethods publickey
PermitEmptyPasswords no
MaxAuthTries 3
ClientAliveInterval 300
ClientAliveCountMax 2
X11Forwarding no
AllowTcpForwarding no
AllowUsers deploy

A few notes:

  • `PermitRootLogin no`—the single most impactful change. Attackers brute-force root constantly.
  • `PasswordAuthentication no`—forces key-based auth. No key, no entry.
  • `AllowUsers deploy`—whitelist. Even if another user exists, they can't SSH in.
  • `MaxAuthTries 3`—disconnects after three failed attempts per session.

If you use a non-standard port, replace Port 22 with e.g. Port 2222. Security through obscurity isn't real protection, but it does cut log noise from automated scanners by roughly 90%.

On Ubuntu 24.04 and newer, also check /etc/ssh/sshd_config.d/ for drop-in files that might override your settings:

bash
grep -r PasswordAuthentication /etc/ssh/sshd_config.d/

If any drop-in re-enables password auth, fix or remove it.

Step 4: Validate and Reload SSH#

Before restarting the daemon, validate syntax:

bash
sshd -t

If there are no errors, reload:

bash
systemctl reload sshd

Keep your existing root session open. Open a second terminal and test deploy login with your key. If it fails, you still have the root shell to fix things.

Step 5: Install and Configure fail2ban#

fail2ban watches log files and bans IPs after repeated failures. Install it:

bash
# Debian/Ubuntu
apt install fail2ban -y

# AlmaLinux/RHEL
dnf install epel-release -y && dnf install fail2ban -y

Create a local config (never edit jail.conf directly):

bash
cat > /etc/fail2ban/jail.local << 'EOF'
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 3
banaction = iptables-multiport

[sshd]
enabled = true
port = 22
filter = sshd
logpath = /var/log/auth.log
EOF

On RHEL-family, change logpath to /var/log/secure. Start and enable it:

bash
systemctl enable --now fail2ban

Verify it's running:

bash
fail2ban-client status sshd

You should see Currently banned: 0 and Currently failed: 0. After a few hours of internet exposure, that banned count will climb—that's fail2ban doing its job.

Step 6: Enable Automatic Security Updates#

Unattended upgrades close known CVEs while you sleep:

bash
# Debian/Ubuntu
apt install unattended-upgrades -y
dpkg-reconfigure -plow unattended-upgrades

# AlmaLinux/RHEL
dnf install dnf-automatic -y
sed -i 's/apply_updates = no/apply_updates = yes/' /etc/dnf/automatic.conf
systemctl enable --now dnf-automatic.timer

Step 7: Verify Everything#

Run through this checklist from a new terminal:

  1. ssh [email protected]—should be rejected immediately.
  2. ssh [email protected]—should prompt for your key passphrase, then log in.
  3. sudo whoami—should return root (confirm sudo works).
  4. fail2ban-client status sshd—daemon is active.
  5. sshd -t—no config errors.

If all five pass, close your old root session. You're done.

Wrapping Up#

This ten-minute lockdown eliminates the two most common initial attack vectors on hosting servers: password brute-force and root login exploitation. It's not a complete security posture—you still need a firewall (UFW or firewalld), kernel tuning, and application-level isolation—but it's the foundation everything else rests on.

If you're running a multi-server operation with tools like Salieno Core, bake these steps into your provisioning templates so every new node ships hardened by default. The worst time to think about SSH security is after you've already loaded customer data onto the box.

Share

0 comments

Loading comments…

More from the blog

Harden SSH & Disable Root Login: 10-Minute Lockdown Guide · Salieno Blog