SSH Hardening — AlmaLinux 9
Step-by-step instructions to harden SSH against brute-force attacks. These steps disable password auth, limit connection attempts, optionally change the port, and enable fail2ban.
Files you'll edit
| File | Purpose |
|---|---|
/etc/ssh/sshd_config |
SSH daemon configuration |
/etc/fail2ban/jail.d/sshd.local |
fail2ban sshd jail override |
Quick reference — vi commands
| Action | Keys |
|---|---|
| Start editing | i |
| Search | / then type what to find, Enter, then n for next match |
| Save & quit | Escape then :wq Enter |
| Quit without saving | Escape then :q! Enter |
Step 1 — Disable password authentication
Open the SSH config:
sudo vi /etc/ssh/sshd_config
Find and change these lines:
#PasswordAuthentication yes → PasswordAuthentication no
AlmaLinux 9 (OpenSSH 8.7+): ChallengeResponseAuthentication was renamed to KbdInteractiveAuthentication. Add at the end of the file:
KbdInteractiveAuthentication no
Older releases: If ChallengeResponseAuthentication exists, change it:
#ChallengeResponseAuthentication yes → ChallengeResponseAuthentication no
If neither option exists in the file, append the one matching your release to the end.
For each one: search with /, press i to edit, remove the # and change yes to no, then Escape.
Step 2 — Lower MaxStartups
Still in /etc/ssh/sshd_config, find and change:
#MaxStartups 10:30:60 → MaxStartups 5:30:60
This limits unauthenticated connections so a flood of half-open connections can't exhaust SSH.
Save and exit: Escape, then :wq, Enter.
Step 3 — (Optional) Change SSH port
Changing from port 22 to a non-standard port (e.g. 2222) eliminates the vast majority of automated attacks.
In /etc/ssh/sshd_config, find and change:
#Port 22 → Port 2222
Then open the new port in the firewall (run this before closing port 22):
sudo firewall-cmd --permanent --add-port=2222/tcp
sudo firewall-cmd --reload
Step 4 — Enable fail2ban sshd jail
Create the jail override file (.local files override the defaults in jail.conf):
sudo vi /etc/fail2ban/jail.d/sshd.local
Press i, then type the following:
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/secure
maxretry = 5
bantime = 3600
findtime = 600
Press Escape, then :wq, Enter.
Note:
/etc/fail2ban/jail.d/*.localis the standard location for local overrides on AlmaLinux. The oldjail.local(single file at/etc/fail2ban/jail.local) also works if you prefer a single file, butjail.d/is cleaner for managing multiple jails.
Step 5 — Restart services
sudo systemctl restart fail2ban
sudo systemctl restart sshd
Step 6 — Test before closing port 22
Keep this web console open. Open a second terminal and test SSH on the new port (or with key-only auth on port 22):
ssh -p 2222 user@your-server
If it works, proceed to Step 7. If not, fix from this web console — it's independent of the network.
Step 7 — Close port 22 (only if changing port)
Once the new port is confirmed working, close the old one:
sudo firewall-cmd --permanent --remove-service=ssh
sudo firewall-cmd --reload
(If port 22 was added manually rather than as a service, use --remove-port=22/tcp instead.)
Step 8 — Verify fail2ban
sudo fail2ban-client status sshd
You should see the sshd jail listed with ban statistics.
Full sequence summary
| Step | Command(s) | What it does |
|---|---|---|
| 1 | Edit /etc/ssh/sshd_config |
Disable password auth |
| 2 | Edit /etc/ssh/sshd_config |
Lower MaxStartups |
| 3 | Edit /etc/ssh/sshd_config + firewall |
Change SSH port (optional) |
| 4 | Create /etc/fail2ban/jail.local |
Enable sshd jail |
| 5 | systemctl restart fail2ban sshd |
Apply everything |
| 6 | Test from separate terminal | Confirm it works |
| 7 | firewall-cmd |
Remove port 22 (if changing port) |
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
Permission denied (publickey) |
Password auth disabled but no key deployed | Use web console to add your public key to ~/.ssh/authorized_keys |
Connection refused |
Wrong port or firewall blocking | Check Port in sshd_config, check firewall-cmd --list-all |
connect to port 2222: No route to host |
SELinux blocking nginx proxy | setsebool -P httpd_can_network_connect 1 |
open() "/home/user/website/static/..." failed (13: Permission denied) |
nginx cannot traverse the home directory to reach files | chmod +x /home/user /home/user/website — grants execute (traverse) permission without exposing other files |