Web Security

How to secure a server: a Linux hardening checklist

How to secure a server: a Linux hardening checklist

Updated October 2026 for AlmaLinux 9 and Ubuntu 24.04.

Most servers that get broken into weren’t hit by anything clever. They had a password login open to the internet, a package nobody patched, or a management port somebody forgot about. This checklist closes those holes on a fresh AlmaLinux 9 or Ubuntu 24.04 server, in the order we’d do it, with the commands for both.

None of it needs a security team. It needs about an hour and a second terminal window.

Before you touch anything: don’t lock yourself out

Half of this list changes how you log in, and one wrong step over SSH locks you out. Keep your current session open while you test from a second one, and know how you’ll reach the console if SSH dies. On a dedicated server that’s the out-of-band controller: IPMI, iLO or iDRAC. We’ll come back to keeping that controller off the public internet, because it’s the most dangerous port on the machine.

The checklist at a glance

TaskAlmaLinux 9Ubuntu 24.04
Admin group for sudowheelsudo
SSH service namesshdssh
Firewall managerfirewalld (nftables backend)ufw (off by default)
Automatic updatesdnf-automaticunattended-upgrades (installed by default)
fail2banFrom EPELFrom the Ubuntu archive
Mandatory access controlSELinux, enforcingAppArmor, loaded
Time syncchronydsystemd-timesyncd
Audit daemonauditd, normally preinstalledapt install auditd

1. Run a supported OS, then patch it

All your other work is wasted on an operating system that no longer gets fixes. CentOS 7 reached end of life on June 30, 2024, and we still see it in the wild. If you’re on it, plan the move now. Once the OS is end of life, the software on top of it stops getting updates too.

AlmaLinux 9 gets security updates until May 31, 2032. Ubuntu 24.04’s standard security maintenance runs to May 2029. Either one is a sane base for a new server today. Bring it fully up to date before you do anything else:

# AlmaLinux 9
sudo dnf upgrade --refresh

# Ubuntu 24.04
sudo apt update && sudo apt full-upgrade

Reboot if the kernel changed. On AlmaLinux, dnf needs-restarting -r tells you; on Ubuntu, look for /var/run/reboot-required.

2. Work as a normal user with sudo

Don’t do daily work as root. Create your own account, put it in the admin group, and use sudo when you need it. Every privileged command then carries your name in the logs.

# AlmaLinux 9
sudo useradd -m -G wheel alex
sudo passwd alex

# Ubuntu 24.04 (root is already locked by default)
sudo adduser alex
sudo adduser alex sudo

Least privilege applies to service accounts too. A deploy user that only needs to restart one service shouldn’t get full root. Give it exactly that, in its own file edited through visudo so a typo can’t break sudo for everyone:

sudo visudo -f /etc/sudoers.d/deploy

# contents:
deploy ALL=(root) /usr/bin/systemctl restart myapp.service

Give your admin account a strong password even after you switch to keys. Sudo asks for it, and 1234 shouldn’t be all that stands between an intruder and root.

3. SSH keys only, no root login

Password logins are what the bots are guessing at all day. Switch to keys and they’re guessing at nothing. From your workstation:

ssh-keygen -t ed25519
ssh-copy-id alex@your-server-ip

Log in with the key in a new terminal and confirm it works. Only then turn passwords off. Both distros read drop-in files from /etc/ssh/sshd_config.d/, and for most settings sshd keeps the first value it reads, so a file named 00- wins over anything an installer or cloud-init dropped in later:

sudo tee /etc/ssh/sshd_config.d/00-hardening.conf <<'EOF'
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
# Optional: only these accounts may log in over SSH
AllowUsers alex
EOF

Check the syntax, confirm the settings sshd will actually use, then reload:

sudo sshd -t
sudo sshd -T | grep -Ei '^(permitrootlogin|passwordauthentication|kbdinteractiveauthentication)'

# AlmaLinux 9
sudo systemctl reload sshd

# Ubuntu 24.04
sudo systemctl restart ssh

Keys have one real cost: you need your private key on any machine you connect from. Add a second key for a spare laptop rather than turning passwords back on. If you run cPanel, WHM supports two-factor authentication for the control panel logins, and it’s worth turning on.

4. Default-deny firewall

A firewall is only as good as its rules, and the approach hasn’t changed in years: block everything inbound, open service ports to everyone, and open admin ports only to the addresses you manage from. A web server needs 80 and 443 open to the world. SSH needs to be open to you.

What has changed is the plumbing. Both distros now run on nftables underneath, so drop the old hand-written iptables scripts and use the tool your OS ships. Pick one manager and stick with it; two tools fighting over the same rules is how ports end up open by accident.

On AlmaLinux 9, firewalld is normally installed and running (if not, sudo dnf install firewalld and sudo systemctl enable --now firewalld), and its public zone allows ssh, cockpit and dhcpv6-client out of the box. Swap open SSH for SSH from your admin IP (198.51.100.25 here), drop cockpit if you don’t use it, and open web traffic:

sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="198.51.100.25/32" service name="ssh" accept'
sudo firewall-cmd --permanent --remove-service=ssh
sudo firewall-cmd --permanent --remove-service=cockpit
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
sudo firewall-cmd --list-all

On Ubuntu 24.04, ufw is disabled by default (sudo apt install ufw if your image lacks it). Add the SSH rule before you enable it:

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow proto tcp from 198.51.100.25 to any port 22
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose

No static IP? Limit SSH to your ISP’s range or a VPN you control. Failing that, keys-only SSH with fail2ban watching it is still far safer than it sounds. One trap on Ubuntu: Docker’s published container ports bypass ufw entirely, so check them separately.

5. Automatic security updates

Patching by hand works until the week you’re busy. Then it stops.

On Ubuntu 24.04, unattended-upgrades is already installed and applies security updates daily. Confirm that /etc/apt/apt.conf.d/20auto-upgrades contains:

APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";

Test it with sudo unattended-upgrade -v --dry-run, and read the logs in /var/log/unattended-upgrades/. It won’t reboot unless you set Unattended-Upgrade::Automatic-Reboot "true"; in 50unattended-upgrades.

On AlmaLinux 9, install dnf-automatic and tell it to apply security updates:

sudo dnf install dnf-automatic

# in /etc/dnf/automatic.conf, [commands] section:
upgrade_type = security
apply_updates = yes

sudo systemctl enable --now dnf-automatic.timer

Neither tool will reboot you into a new kernel by default. Schedule a monthly reboot window and check dnf needs-restarting -r or /var/run/reboot-required as part of it.

6. fail2ban for anything with a login

Brute-force bots hammer every login they find. fail2ban reads your logs and bans an IP at the firewall after too many failures. With SSH passwords off it mostly cuts noise there, but it also covers logins that still take passwords, like mail and FTP.

# AlmaLinux 9 (fail2ban comes from EPEL)
sudo dnf config-manager --set-enabled crb
sudo dnf install epel-release
sudo dnf install fail2ban fail2ban-firewalld

# Ubuntu 24.04
sudo apt install fail2ban

Don’t edit jail.conf; upgrades overwrite it. Put your settings in /etc/fail2ban/jail.local:

[DEFAULT]
bantime  = 1h
findtime = 10m
maxretry = 5
ignoreip = 127.0.0.1/8 ::1 198.51.100.25

[sshd]
enabled = true
backend = systemd

Then sudo systemctl enable --now fail2ban and check it with sudo fail2ban-client status sshd. Ubuntu’s package already enables the sshd jail with the systemd backend, so the file there mostly sets your ban times and whitelist. Your apps need their own protection too. WordPress, cPanel/WHM (cPHulk) and any custom admin page should lock out repeated failures.

7. Leave SELinux or AppArmor enforcing

The most common “fix” in old tutorials is setenforce 0. Don’t. SELinux and AppArmor limit what a compromised service can touch, which is exactly the moment you need them.

# AlmaLinux 9: should say Enforcing
getenforce
sestatus

# Ubuntu 24.04: AppArmor is installed and loaded by default
sudo aa-status

When an app breaks on AlmaLinux, read the denial with sudo ausearch -m AVC -ts recent and fix the label or boolean it points to. If you have to debug live, use permissive mode briefly. Red Hat’s own guidance is not to disable SELinux.

8. Time sync, logs and auditd

Logs with wrong timestamps are close to useless in an investigation. AlmaLinux 9 uses chronyd and Ubuntu 24.04 uses systemd-timesyncd. Check that they’re working:

# AlmaLinux 9
chronyc tracking

# Ubuntu 24.04: look for "System clock synchronized: yes"
timedatectl status

Make sure the journal survives a reboot. If journalctl --list-boots only shows the current boot, set Storage=persistent in a file under /etc/systemd/journald.conf.d/ and restart systemd-journald. Better still, forward logs to another machine, because the first thing a competent intruder does is clean up the local ones.

auditd records who changed what. It’s part of a standard AlmaLinux 9 install (check with systemctl status auditd); on Ubuntu run sudo apt install auditd. A few watch rules on the files attackers like to edit go a long way. Save these as /etc/audit/rules.d/50-local.rules:

-w /etc/sudoers -p wa -k sudoers
-w /etc/sudoers.d/ -p wa -k sudoers
-w /etc/ssh/sshd_config -p wa -k sshd
-w /etc/ssh/sshd_config.d/ -p wa -k sshd

Load them with sudo augenrules --load and search later with sudo ausearch -k sudoers -i.

9. Backups that live somewhere else

A backup on the same server isn’t a backup. Ransomware encrypts it, and an attacker with root deletes it. Keep at least one copy on separate infrastructure, under credentials the server itself can’t use to delete it. Then restore from it on a schedule, because a backup you’ve never restored is a guess. If you’d rather not build that yourself, our Veeam backups store an offsite copy in our data centers, and Veeam Agent covers bare-metal Linux and Windows servers.

10. Keep IPMI off the public internet

The out-of-band controller is a separate computer inside your server with its own network port, and it can power-cycle, reinstall and take over the console. BMC firmware has a long history of serious bugs, and CISA’s advice has been the same for years: keep IPMI on a restricted management network, never on the open internet, with strong unique passwords.

On GigeNET dedicated servers, IPMI sits on a private management network by default, so the console isn’t exposed on a public IP. That holds whether the server is managed or self-managed. If you run hardware elsewhere, check where that port is plugged in.

11. Your apps and custom code

A hardened OS won’t save a site running a three-year-old plugin. Keep WordPress, Joomla or Magento current, plugins and themes included, and replace any plugin that’s been abandoned.

Watch your language runtimes too. PHP 8.1 and everything older is past end of life, and 8.2 only gets security fixes until December 31, 2026. On CloudLinux, which a lot of cPanel servers run, HardenedPHP keeps old branches back to PHP 4.4 patched, which buys time for a legacy site. It isn’t a reason to stay on PHP 5 forever.

Custom code is the hardest part, because your host can’t patch software it didn’t write. Keep a relationship with whoever built it, or one day you won’t be able to upgrade PHP because the site won’t run on anything newer.

Rather have someone else do the patching?

If nobody on your team owns patching and monitoring, our Enterprise Server Management plan ($99/month per server, or $79 with a cPanel license) covers OS updates and security patches, which we schedule with you, plus advanced monitoring of load, RAID, swap, services and website uptime, and troubleshooting and server administration. Server hardening, malware protection and backups are separate options on the order form. Tell us what you’re running on the custom quote form and we’ll spec the server and the plan to fit.

FAQ

What should I do first on a new Linux server?

Patch it, create your own sudo user, and get key-based SSH working. Then turn off password and root login and put a default-deny firewall in place. Everything else on this list can follow the same day.

Should I move SSH off port 22?

It cuts log noise, but it doesn’t add much security. Keys-only login and an IP allowlist do the real work. If you do move it on AlmaLinux, SELinux has to be told about the new port, and so does your firewall.

An app broke after I installed it. Can I just disable SELinux?

You can, and you shouldn’t. Check the denial with ausearch -m AVC, then fix the file label or turn on the SELinux boolean the app needs. Permissive mode is fine for a short debugging session, not as a permanent setting.

Is IPMI safe on the internet if it has a strong password?

No. BMCs have had authentication bypass bugs that a password doesn’t stop. Keep IPMI on a private management network and reach it over a VPN or your provider’s access method.