LINUX TUTORIAL

Hardening the SSH server

Narrow what SSH accepts: no root login, a user whitelist, limited attempts, and fail2ban, then reload safely without locking yourself out.

What we're doing

We harden the SSH server: no root login, a user whitelist, limited attempts, and fail2ban. One habit runs through all of it. Keep the web terminal open as a fallback, test the config before reloading, and confirm a fresh login still works. Key login to localhost already works and passwords are already off (from SEC-001), and there is a spare intern account to test the whitelist.

Watch the video first, then run these as we go. These change the SSH server's config, so they need sudo. We verify against localhost.

The one rule: don't lock yourself out

A bad SSH config can lock us out of our own server. So:

  1. Keep the session we already have open (here, the web terminal, it is not SSH, so no sshd change drops it).
  2. sudo sshd -t to test the config (a typo stops here, before it goes live).
  3. sudo systemctl reload ssh (re-read config, keep open connections).
  4. Open a fresh login (ssh localhost) and confirm it works before trusting the change.

What hardening closes

Setting What it does
PermitRootLogin no no logging in directly as root (log in as a user, then sudo)
AllowUsers <user> whitelist; anyone not listed is refused before auth
MaxAuthTries 3 drop the connection after 3 failed attempts
PasswordAuthentication no key only (set in SEC-001)
fail2ban bans an IP that keeps failing in the SSH log

Step 1: write the hardening settings

sudo tee /etc/ssh/sshd_config.d/10-hardening.conf >/dev/null <<EOF
PermitRootLogin no
MaxAuthTries 3
AllowUsers $(whoami)
EOF

A drop-in file with three settings. $(whoami) fills in our own username for the whitelist.

Step 2: test, then reload (safely)

sudo sshd -t                 # test the config FIRST; nothing printed = valid
sudo systemctl reload ssh    # apply without dropping open connections

Step 3: verify the lockdown

sudo sshd -T | grep -Ei 'permitrootlogin|maxauthtries|allowusers|passwordauthentication'   # effective config
ssh -o BatchMode=yes root@localhost      # root: refused
ssh -o BatchMode=yes intern@localhost    # not on the whitelist: refused
ssh localhost whoami                     # us: still works
permitrootlogin no
passwordauthentication no
maxauthtries 3
allowusers preparesh
root@localhost: Permission denied (publickey).
intern@localhost: Permission denied (publickey).
preparesh

sshd -T prints the effective config (all files merged). Root and the non-whitelisted intern are refused; our own key login still works, so we are not locked out.

Step 4: switch on fail2ban

sudo tee /etc/fail2ban/jail.local >/dev/null <<'EOF'
[sshd]
enabled = true
maxretry = 4
bantime = 1h
EOF
sudo systemctl restart fail2ban
sudo fail2ban-client status sshd
Status for the jail: sshd
   ...
   |- Currently banned: 0
   `- Banned IP list:

fail2ban watches the SSH log and bans an IP after maxretry failures, for bantime. (We can't trigger it from here, fail2ban ignores localhost by default, but on a real server an attacker's IP gets banned automatically.)

Cheat sheet

# harden (in a drop-in)
sudo tee /etc/ssh/sshd_config.d/10-hardening.conf >/dev/null <<EOF
PermitRootLogin no
MaxAuthTries 3
AllowUsers $(whoami)
EOF
sudo sshd -t && sudo systemctl reload ssh      # ALWAYS test before reload

# verify
sudo sshd -T | grep -Ei 'permitrootlogin|allowusers|maxauthtries|passwordauthentication'
ssh -o BatchMode=yes root@localhost            # should be refused
ssh localhost whoami                           # should still work

# fail2ban
sudo systemctl restart fail2ban
sudo fail2ban-client status sshd

In short: narrow SSH to the minimum, no root, only whitelisted users, key-only, limited tries, with fail2ban banning repeat offenders. And the rule that keeps it safe: keep the session we already have open, sshd -t before every reload, and confirm a fresh login works before trusting the change.

Next tutorial: once someone is logged in, what they can do, users, groups, and sudo.


What's next

Just hit Start and go try this out in a live environment !

Start LINUX
Spec 2 CPU / 4 GiB ·Disk 25 GiB ·Lifetime 7 days
Before you start — your account isn't verified, so outbound internet will be restricted. We recommend verifying for free to enable it.
Sign in to launch this environment
Required 1 VM · 2 CPU · 4 GB · 25 GiB disk
Available 1 VM · 1 CPU · 2 GB · 10 GiB disk
Sign in