Updated: 22 October 2026 · Applies to: AlmaLinux 10.2 and Rocky Linux 9.8 (tested), RHEL 9 and 10 (according to Red Hat); notes for servers still on CentOS 7
The steps that make the biggest difference on a CentOS-family server are: keep it updated, log in with SSH keys instead of root passwords, close every port you do not use, block repeated login attempts, and leave SELinux enforcing. Everything else in this guide builds on those five. If the server still runs CentOS Linux 7 or 8, the most important step comes first: move it to a supported system.
Before you start: is your CentOS still supported?
CentOS Linux 8 reached end of life on 31 December 2021 and CentOS Linux 7 on 30 June 2024, so neither gets security updates any more. No setting below can fix an operating system without patches. Move to AlmaLinux or Rocky Linux 9 or 10 (or RHEL); the commands in this guide are the same on all of them. Keep a full backup before any migration.
All commands below run as root or with sudo.
1. Install updates, and install them automatically
dnf upgrade --refresh
To install updates without waiting for you, enable dnf-automatic:
dnf install dnf-automatic systemctl enable --now dnf-automatic-install.timer
The dnf-automatic-install timer downloads and installs updates once a day (06:00 plus a random delay of up to an hour on our AlmaLinux 10.2 system), even though /etc/dnf/automatic.conf says apply_updates = no, because that timer runs dnf-automatic with --installupdates. It does not reboot by default (reboot = never).
To apply only security fixes, see How to Install Only Security Updates with yum and dnf. Reboot after kernel updates.
2. Create an admin user and use sudo
Work as a normal user and use sudo for admin tasks. Members of the wheel group may use sudo by default:
useradd -m -G wheel alice passwd alice
Log in as that user in a new session and check that sudo -i works before you change any root login settings.
3. Use SSH keys and turn off root and password logins
Copy your public key to the server from your own computer:
ssh-copy-id alice@203.0.113.10
Replace the address with your server's IP. When key login works, create a settings file in sshd's drop-in folder. sshd uses the first value it reads for each option, and files are read in name order. Our AlmaLinux 10.2 system already had 25-permitrootlogin.conf (with PermitRootLogin yes) and 50-redhat.conf there, so give your file a name that sorts before them:
nano /etc/ssh/sshd_config.d/10-hardening.conf
(If nano is missing, install it with dnf install nano or use vi.) Put these lines in the file:
PermitRootLogin no PasswordAuthentication no KbdInteractiveAuthentication no
Check the configuration and see which values sshd will really use:
sshd -t sshd -T | grep -E '^(port|permitrootlogin|passwordauthentication|kbdinteractiveauthentication) '
Output on our AlmaLinux 10.2 system (before the file, it showed permitrootlogin yes and passwordauthentication yes; the port line shows 2222 because we also set the port from step 4):
port 2222 permitrootlogin no passwordauthentication no kbdinteractiveauthentication no
sshd -t prints nothing when the syntax is correct. On Rocky Linux 9.8 the default was permitrootlogin without-password (root may log in with a key only) and the same file switched it to no.
Then restart SSH, and keep your current session open until you have logged in again from a second window:
systemctl restart sshd
For more sshd options, see Increasing the security of your server: sshd hardening.
4. Change the SSH port (optional)
According to Red Hat, a different port "provides only limited security benefits", because a full port scan still finds it, but it does cut down the automated login noise in your logs. If you change it, three things must agree: sshd, SELinux and the firewall. Add a Port line (for example Port 2222) to your drop-in file, then:
dnf install policycoreutils-python-utils semanage port -a -t ssh_port_t -p tcp 2222
firewall-cmd --permanent --add-port=2222/tcp firewall-cmd --reload systemctl restart sshd
The semanage line tells SELinux that sshd may listen on 2222; without it, sshd cannot use the new port while SELinux is enforcing. Log in on the new port from a second window (ssh -p 2222 alice@203.0.113.10). Only when that works, close the standard SSH service in the firewall:
firewall-cmd --permanent --remove-service=ssh firewall-cmd --reload
Red Hat's own example removes 22/tcp as a port, but a default AlmaLinux zone allows SSH as the ssh service, so remove the service instead. The SELinux step is according to Red Hat (a container cannot change SELinux policy); we checked the firewall changes in our lab with firewall-offline-cmd.
Full steps, including Ubuntu, are in What Is the Default SSH Port and How to Change It Safely.
5. Close ports you do not use
firewalld is the standard firewall on AlmaLinux, Rocky and RHEL. See what the default zone allows:
firewall-cmd --list-all
Part of the output on a fresh AlmaLinux 10.2 system (our lab, read with firewall-offline-cmd --list-all, which prints the same format):
public (default) target: default services: cockpit dhcpv6-client ssh ports:
cockpit is the web console on port 9090. If you do not use it, close it, and open only what your server really serves (for example http and https for a web server):
firewall-cmd --permanent --remove-service=cockpit firewall-cmd --permanent --add-service=http --add-service=https firewall-cmd --reload
If the server runs cPanel and WHM, use the firewall your panel supports instead of mixing two firewalls. ConfigServer Firewall (CSF) is now maintained by cPanel as the cpanel-csf package, which according to cPanel installs only on cPanel and WHM servers; old guides that download csf.tgz from configserver.com no longer work.
More examples are in firewall-cmd: List All Rules and Useful firewalld Examples.
6. Block repeated login attempts
Fail2Ban reads the logs and blocks an IP address after several failed logins. It comes from EPEL:
dnf install epel-release dnf install fail2ban
In our AlmaLinux 10.2 test this installed Fail2Ban 1.1.0 and firewalld, with bans going through firewalld. No jail is switched on after installing, so create /etc/fail2ban/jail.local:
nano /etc/fail2ban/jail.local
With this content (use your SSH port; 2222 is the example from step 4):
[sshd] enabled = true port = 2222 maxretry = 5 bantime = 1h
Test the configuration, then start the service:
fail2ban-client -t systemctl enable --now fail2ban
Output of the test:
OK: configuration test is successful
On a cPanel server, use WHM's cPHulk Brute Force Protection instead. According to cPanel, it protects cPanel, WHM, mail (Dovecot and Exim), Pure-FTPd and SSH logins, and you switch it on with the toggle in WHM, Security Center, cPHulk Brute Force Protection.
7. Leave SELinux enforcing
getenforce
It should print Enforcing. Many old guides tell you to disable SELinux when something does not work; fix the label or port instead (as with semanage above), because SELinux limits what an attacker can do through a hacked web application.
8. Remove services and packages you do not need
Every running service is something that can be attacked. List what listens on the network and what starts at boot:
ss -tulpn
systemctl list-unit-files --type=service --state=enabled
For each service you do not need, stop it now and stop it starting at boot (replace SERVICE with the unit name from the list):
systemctl disable --now SERVICE
Then remove packages you never use with dnf remove PACKAGE. Fewer packages also means fewer updates to apply.
9. Scan for malware and rootkits
Linux servers do get malware, usually through weak passwords or outdated web applications. Run a scanner now and then:
- How to Install and Use rkhunter (Rootkit Hunter) on Linux
- Three Tools to Scan a Linux Server for Viruses, Malware and Rootkits (ClamAV and others)
- VPS Security Audits Using Lynis for a full checklist of your setup
10. Back up, and keep the backup somewhere else
Security is never complete, so plan for the day something goes wrong. Back up files and databases daily to a different server or storage, and test a restore now and then. A backup on the same disk is lost together with the server.
A note on network files: ifcfg is gone
Older CentOS 7 guides edit files in /etc/sysconfig/network-scripts/ifcfg-*. Those set network addresses, not security, and on current systems they no longer apply: AlmaLinux, Rocky and RHEL 9 store connections as NetworkManager keyfiles in /etc/NetworkManager/system-connections/, and according to Red Hat, version 10 ignores ifcfg files completely. On version 9 you can convert old files with:
nmcli connection migrate
To change an IP address with nmcli, or on Ubuntu, follow How to Set a Static IP Address from the Linux Command Line (CentOS, AlmaLinux, Rocky Linux, RHEL and Ubuntu).
If you would rather have our team harden the server for you, see Hire an Expert.
Official documentation: Red Hat Enterprise Linux 10: Securing networks.