A fresh Linux server is not a hardened Linux server. Whether you are spinning up a VPS, provisioning bare metal, or deploying a cloud instance, a consistent hardening pass before the box sees production traffic is non-negotiable. This checklist covers the essentials for Ubuntu/Debian and RHEL/AlmaLinux/Rocky systems in 2026.
1. SSH hardening
SSH is typically the only remote access vector on a new server, so lock it down first. Edit /etc/ssh/sshd_config (or drop a file in /etc/ssh/sshd_config.d/):
PermitRootLogin no PasswordAuthentication no PubkeyAuthentication yes AuthenticationMethods publickey KbdInteractiveAuthentication no X11Forwarding no MaxAuthTries 3 LoginGraceTime 20 AllowUsers deployer admin
Restart the daemon after changes:
sudo systemctl restart sshdUse Ed25519 keys. If you still have RSA keys, ensure they are at least 4096 bits. Generate a new key pair:
ssh-keygen -t ed25519 -C "yourname@host"Consider moving SSH to a non-standard port to reduce noise in logs. This is not security, but it cuts automated scan traffic significantly.
Ref: man sshd_config, man ssh-keygen
2. Firewall defaults
Default-deny inbound. Allow only what you need. On Ubuntu/Debian, ufw is the simplest front-end:
sudo ufw default deny incoming sudo ufw default allow outgoing sudo ufw allow 22/tcp comment 'SSH' sudo ufw allow 443/tcp comment 'HTTPS' sudo ufw enable sudo ufw status verbose
On RHEL/AlmaLinux/Rocky, use firewalld:
sudo firewall-cmd --set-default-zone=drop sudo firewall-cmd --zone=drop --add-service=ssh --permanent sudo firewall-cmd --zone=drop --add-service=https --permanent sudo firewall-cmd --reload sudo firewall-cmd --list-all
If you use raw nftables, define your ruleset in /etc/nftables.conf and enable nftables.service. Avoid mixing front-ends with direct nftables rules.
Ref: man ufw, man firewall-cmd, man nft
3. Unattended security updates
Patch delay is one of the most common root causes of compromise. Automate security patches at minimum.
Ubuntu/Debian — install and configure unattended-upgrades:
sudo apt install unattended-upgrades sudo dpkg-reconfigure -plow unattended-upgrades
Verify the config in /etc/apt/apt.conf.d/50unattended-upgrades. Ensure "${distro_id}:${distro_codename}-security" is enabled. Optionally enable automatic reboot for kernel patches:
Unattended-Upgrade::Automatic-Reboot "true"; Unattended-Upgrade::Automatic-Reboot-Time "04:00";
RHEL/AlmaLinux/Rocky — use dnf-automatic:
sudo dnf install dnf-automatic sudo systemctl enable --now dnf-automatic-install.timer
Edit /etc/dnf/automatic.conf and set upgrade_type = security to restrict to security patches only.
Ref: man unattended-upgrades, man dnf-automatic
4. Brute-force protection: fail2ban and CrowdSec
Even with key-only SSH, brute-force attempts pollute logs and waste resources. Two solid options:
fail2ban is the established choice. It watches log files and bans IPs after repeated failures:
# Ubuntu/Debian sudo apt install fail2ban # RHEL (EPEL required) sudo dnf install epel-release sudo dnf install fail2ban
Create /etc/fail2ban/jail.local to override defaults without touching the package file:
[DEFAULT] bantime = 1h findtime = 10m maxretry = 3 [sshd] enabled = true port = ssh
sudo systemctl enable --now fail2ban sudo fail2ban-client status sshd
CrowdSec is the newer, community-driven alternative. It parses logs like fail2ban but shares threat intelligence across its network, giving you blocklists crowdsourced from other nodes:
# Install CrowdSec (all distros) curl -s https://install.crowdsec.net | sudo bash sudo apt install crowdsec crowdsec-firewall-bouncer-iptables # Debian/Ubuntu sudo dnf install crowdsec crowdsec-firewall-bouncer-iptables # RHEL
CrowdSec detects attacks via "scenarios" and blocks via "bouncers." The firewall bouncer plugs into iptables/nftables. Check decisions with:
sudo cscli decisions listChoose one or the other; running both on the same logs is redundant.
Ref: man fail2ban, man jail.conf, CrowdSec docs at docs.crowdsec.net
5. Audit and logging
Without logs, you cannot investigate incidents. Configure the audit subsystem and centralize logs.
auditd — install and enable:
# Ubuntu/Debian sudo apt install auditd # RHEL (usually pre-installed) sudo dnf install audit
sudo systemctl enable --now auditd Add rules to watch sensitive files. Append to /etc/audit/rules.d/hardening.rules:
# Watch for changes to user/group databases -w /etc/passwd -p wa -k identity -w /etc/shadow -p wa -k identity -w /etc/group -p wa -k identity -w /etc/sudoers -p wa -k sudoers -w /etc/sudoers.d/ -p wa -k sudoers # Watch SSH config -w /etc/ssh/sshd_config -p wa -k sshd_config # Log all commands run as root -a always,exit -F arch=b64 -F euid=0 -S execve -k root_commands
Load the rules:
sudo augenrules --loadSearch audit logs:
sudo ausearch -k identity --interpretjournald — ensure persistent storage is enabled. Check that /etc/systemd/journald.conf has:
Storage=persistent SystemMaxUse=500M
Forward logs to a remote syslog collector (rsyslog, Loki, or a SIEM) so that an attacker who gains root cannot erase evidence from the local box.
Ref: man auditd, man audit.rules, man ausearch, man journald.conf
6. User and privilege management
Minimize attack surface from user accounts:
- Remove or lock unnecessary user accounts:
sudo usermod -L -s /usr/sbin/nologin olduser - Limit sudo access. Avoid
ALL=(ALL) NOPASSWD: ALL. Grant specific commands per role. - Use
visudoto edit sudoers safely. Drop role files in/etc/sudoers.d/. - Set password policy with PAM. On RHEL,
authselectmanages PAM profiles cleanly. - Enforce password aging:
sudo chage -M 90 -W 14 username
Audit which users have sudo access:
grep -r 'NOPASSWD\|ALL' /etc/sudoers /etc/sudoers.d/Ref: man sudoers, man chage, man authselect
7. Kernel and network parameters
Harden the network stack via /etc/sysctl.d/99-hardening.conf:
# Ignore ICMP redirects net.ipv4.conf.all.accept_redirects = 0 net.ipv6.conf.all.accept_redirects = 0 # Don't send ICMP redirects net.ipv4.conf.all.send_redirects = 0 # Enable SYN flood protection net.ipv4.tcp_syncookies = 1 # Ignore source-routed packets net.ipv4.conf.all.accept_source_route = 0 net.ipv6.conf.all.accept_source_route = 0 # Log martian packets net.ipv4.conf.all.log_martians = 1 # Disable IP forwarding (unless this is a router/VPN gateway) net.ipv4.ip_forward = 0 # Restrict kernel pointer exposure kernel.kptr_restrict = 2 # Restrict dmesg access kernel.dmesg_restrict = 1
sudo sysctl --systemRef: man sysctl.conf, kernel docs at Documentation/networking/ip-sysctl.rst
8. Service minimization
Every running service is attack surface. List enabled services and disable what you do not need:
systemctl list-unit-files --type=service --state=enabled sudo systemctl disable --now cups avahi-daemon rpcbind
Check listening ports and verify you recognise every one:
sudo ss -tlnpRemove packages you do not need. On RHEL minimal installs this is less of an issue, but Ubuntu server can ship with extras.
9. File integrity and rootkit detection
Detect unauthorized file changes before they become incidents:
# AIDE (Advanced Intrusion Detection Environment) sudo apt install aide # Debian/Ubuntu sudo dnf install aide # RHEL sudo aideinit # Debian/Ubuntu: initialize database sudo aide --init # RHEL: initialize database # Run a check sudo aide --check
Schedule a daily check via cron or a systemd timer. Store the baseline database offline or on a separate system.
For rootkit scanning, rkhunter and chkrootkit remain useful as a quick sanity check:
sudo apt install rkhunter # or sudo dnf install rkhunter sudo rkhunter --update sudo rkhunter --check --skip-keypress
Ref: man aide, man rkhunter
10. Backup validation
Backups you have never restored are not backups. They are hopes.
- Test restores regularly. Schedule a quarterly restore drill to a scratch VM.
- Verify integrity. Use checksums or cryptographic signatures on backup archives.
- Follow the 3-2-1 rule: 3 copies, 2 different media types, 1 offsite.
- Encrypt backups at rest. A stolen backup is a data breach.
A minimal verification script using restic (works on all distros):
# Check repository integrity restic -r /path/to/repo check # List snapshots restic -r /path/to/repo snapshots # Test restore of a specific path restic -r /path/to/repo restore latest --target /tmp/restore-test --include /etc
Whatever tool you use (restic, borg, rsnapshot, Veeam), the principle is the same: automate the backup, but also automate the verification.
11. Patch cadence
Automated security updates (section 3) handle the urgent patches, but you still need a scheduled cadence for all updates:
- Weekly: review pending updates, apply in staging.
- Bi-weekly or monthly: apply tested updates to production with a maintenance window.
- Immediately: critical CVEs with active exploitation. Subscribe to your distro's security mailing list.
Check for available updates:
# Ubuntu/Debian apt list --upgradable # RHEL dnf check-update --security
On Ubuntu, ubuntu-advantage (now pro) provides Livepatch for kernel updates without reboot. RHEL offers kpatch. Both are worth evaluating for uptime-critical systems.
Security mailing lists:
- Ubuntu:
ubuntu-security-announce - Debian:
debian-security-announce - RHEL:
rhsa-announcevia Red Hat mailing lists
Quick reference checklist
[ ] SSH: key-only auth, root login disabled, MaxAuthTries 3 [ ] Firewall: default-deny inbound, only required ports open [ ] Auto-updates: unattended-upgrades or dnf-automatic for security patches [ ] Brute-force: fail2ban or CrowdSec active on SSH (and web if applicable) [ ] Audit: auditd rules for /etc/passwd, /etc/shadow, sudoers, sshd_config [ ] Logging: journald persistent, logs forwarded to remote collector [ ] Users: no unnecessary accounts, sudo scoped to specific commands [ ] Kernel: sysctl hardening applied, IP forwarding off [ ] Services: unused daemons disabled, listening ports reviewed [ ] Integrity: AIDE or similar baselined, rootkit scanner scheduled [ ] Backups: 3-2-1 rule, restore tested, encrypted at rest [ ] Patches: cadence defined, security mailing lists subscribed
No checklist replaces understanding your threat model, but if you walk through these items on every new server, you are ahead of the majority. Revisit quarterly and after any major change.
This work is licensed under a Creative Commons Attribution-NonCommercial 2.5 License .