# Harden SSH AlmaLinux 9: Secure Setup in 15 Minutes

Source: https://srvscripts.com/guides/harden-ssh-almalinux-9/
Updated: 2026-10-03
Publisher: srvScripts (https://srvscripts.com/)

## Before you touch anything

Open a second SSH session and leave it connected. Every change below is applied with `sshd -t` (config test) before a reload, and a reload never drops existing sessions, so if you lock yourself out you still have the first window to undo it.

In short: Open a second SSH session and leave it connected.

Check that the server is actually using `sshd_config` and not a drop-in you did not know about:

```
sshd -T | grep -Ei 'permitrootlogin|passwordauthentication|^port|pubkeyauthentication'
ls /etc/ssh/sshd_config.d/
```

On AlmaLinux 9 the file `/etc/ssh/sshd_config.d/50-redhat.conf` exists and is read **before** the main file. Anything you set in the main file that conflicts with it loses, because sshd keeps the first value it sees. Put your hardening in its own drop-in with a lower number so it wins.

## 1. Install your key, then disable passwords

From your workstation:

```
ssh-keygen -t ed25519 -C "you@workstation"
ssh-copy-id -i ~/.ssh/id_ed25519.pub root@server
```

Log in once with the key to prove it works. Then create `/etc/ssh/sshd_config.d/10-hardening.conf`:

```
PermitRootLogin prohibit-password
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
AuthenticationMethods publickey
MaxAuthTries 3
LoginGraceTime 30
X11Forwarding no
AllowAgentForwarding no
AllowTcpForwarding no
ClientAliveInterval 300
ClientAliveCountMax 2
```

`prohibit-password` lets root in with a key only, which is what most cPanel and DirectAdmin servers need. If you have a sudo user and never need root over SSH, use `PermitRootLogin no` instead. Test and reload:

```
sshd -t && systemctl reload sshd
```

Try a password login from another terminal; it should be refused immediately.

## 2. Change the port without fighting SELinux

Moving off port 22 does not make the server secure, but it removes 95% of the automated noise from your logs and from your brute-force blocker. Pick a port above 1024 that nothing else uses, for example 2222 is too common; 48222 is fine.

SELinux only allows sshd to bind to ports labelled `ssh_port_t`. Add the label first or sshd will fail to start:

```
dnf -y install policycoreutils-python-utils
semanage port -a -t ssh_port_t -p tcp 48222
firewall-cmd --permanent --add-port=48222/tcp && firewall-cmd --reload
echo "Port 48222" >> /etc/ssh/sshd_config.d/10-hardening.conf
sshd -t && systemctl restart sshd
```

Connect on the new port in a new terminal before you close the old one. Only then remove port 22 from the firewall (`firewall-cmd --permanent --remove-service=ssh`). If you use CSF instead of firewalld, add the port to `TCP_IN` in `/etc/csf/csf.conf` and run `csf -r`.

## 3. Rate-limit and ban

With passwords off, brute force cannot succeed, but it still costs CPU and fills `/var/log/secure`. Use whichever blocker the server already has: CSF+LFD (`LF_SSHD = "5"` in csf.conf), cPHulk on cPanel, or fail2ban on a plain box:

```
dnf -y install fail2ban
cat > /etc/fail2ban/jail.d/sshd.local
