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.