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:
- Keep the session we already have open (here, the web terminal, it is not SSH, so no
sshdchange drops it). sudo sshd -tto test the config (a typo stops here, before it goes live).sudo systemctl reload ssh(re-read config, keep open connections).- 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
Start LINUX