Linux Server Hardening: A Complete Step-by-Step Checklist

TL;DR: A fresh Ubuntu or Rocky Linux server is reasonably secure out of the box — but reasonable isn’t enough for anything exposed to the internet. This checklist walks through SSH hardening, firewall rules, fail2ban, automatic security updates, audit logging, and SELinux/AppArmor essentials. Apply it in order on a fresh VM and you’ll close 95% of common attack vectors.

1. Create an admin user and disable root SSH

adduser admin
usermod -aG sudo admin   # Ubuntu/Debian
usermod -aG wheel admin  # RHEL/Rocky

Copy your SSH key to the new user, log in to verify, then edit /etc/ssh/sshd_config: set PermitRootLogin no, PasswordAuthentication no, and Port 2222 (or any non-default port). Restart sshd.

2. Configure the firewall (UFW or firewalld)

# Ubuntu
ufw default deny incoming
ufw default allow outgoing
ufw allow 2222/tcp
ufw allow 80,443/tcp
ufw enable

# Rocky/RHEL
firewall-cmd --permanent --remove-service=ssh
firewall-cmd --permanent --add-port=2222/tcp
firewall-cmd --permanent --add-service={http,https}
firewall-cmd --reload

3. Install fail2ban

Brute-force protection should be running before you put anything online.

apt install fail2ban -y   # Ubuntu
dnf install fail2ban -y   # Rocky

cat > /etc/fail2ban/jail.local <<'EOF'
[sshd]
enabled = true
port = 2222
maxretry = 3
findtime = 10m
bantime = 1h
EOF

systemctl enable --now fail2ban

4. Enable automatic security updates

# Ubuntu
apt install unattended-upgrades -y
dpkg-reconfigure --priority=low unattended-upgrades

# Rocky
dnf install dnf-automatic -y
systemctl enable --now dnf-automatic.timer

5. Lock down kernel and sysctl

Add to /etc/sysctl.d/99-hardening.conf:

net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.tcp_syncookies = 1
kernel.dmesg_restrict = 1
kernel.kptr_restrict = 2

Apply with sysctl -p /etc/sysctl.d/99-hardening.conf.

6. SELinux or AppArmor — leave it ON

On Rocky/RHEL run getenforce; it should report Enforcing. Don’t disable it because a tutorial said so — use audit2allow to write targeted policies instead. On Ubuntu confirm AppArmor with aa-status.

7. Audit logging with auditd

apt install auditd -y   # Ubuntu
dnf install audit -y    # Rocky
systemctl enable --now auditd

Pull a vetted rule set such as the Neo23x0 audit rules to start logging meaningful events (user creation, privilege changes, suspicious binaries).

8. Disable unused services

systemctl list-unit-files --state=enabled
# disable anything you don't need:
systemctl disable --now avahi-daemon cups bluetooth

9. Time, logs, and monitoring

Enable chronyd/NTP. Centralize syslog with rsyslog → a remote log server, or ship logs to Wazuh/Graylog. Without good timestamps and remote logs, incident response is guesswork.

10. Backups before you go live

Schedule restic, borgbackup, or Veeam backups to an offsite immutable target. Test a restore. Now you can go live.

Quick audit checklist

  • SSH on non-default port, root login disabled, key-only auth
  • UFW/firewalld default deny inbound
  • fail2ban active, banning > 0 hosts
  • Unattended-upgrades running
  • SELinux/AppArmor enforcing
  • auditd capturing user, privilege, and file events
  • Time sync working, logs centralized
  • Tested backups within last 7 days

FAQ

Should I change the SSH port?

It’s not security in itself, but it cuts brute-force log noise dramatically. Combine it with key-only auth and fail2ban.

Is Ubuntu or Rocky safer?

Both are equally secure when hardened. Rocky benefits from SELinux being default; Ubuntu has a faster patch cadence. Pick the one your team knows best.

Do I need a host-based IDS?

Yes, for production. Wazuh is free, mature, and integrates beautifully with auditd.

Next steps

Need help hardening a fleet of Linux servers or building a golden image? Talk to a CoreSecTech engineer.

Leave a Comment