A comprehensive server hardening checklist for Ubuntu 24.04, covering SSH configuration, firewall setup, fail2ban, unattended upgrades, CIS benchmarks, audit logging, and kernel hardening.
Introduction
A freshly provisioned Ubuntu server is not secure by default. It ships with a broad attack surface: password-based SSH, no firewall, no intrusion detection, and no automatic patching. Every server we put into production should go through a hardening process before it receives any traffic.
This guide provides a complete, step-by-step hardening checklist for Ubuntu 24.04 LTS. We cover SSH lockdown, firewall configuration, brute-force protection, automatic security updates, kernel hardening, and audit logging. Each section includes the exact commands to run.
1. System Updates
Start by ensuring the system is fully patched:
sudo apt update && sudo apt upgrade -y
sudo apt autoremove -y
2. Create a Non-Root User with SSH Key Access
Never use the root account for day-to-day operations:
adduser deploy
usermod -aG sudo deploy
# Set up SSH key for the new user
mkdir -p /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
# Paste the public key
echo "ssh-ed25519 AAAA... user@workstation" > /home/deploy/.ssh/authorized_keys
chmod 600 /home/deploy/.ssh/authorized_keys
chown -R deploy:deploy /home/deploy/.ssh
3. Harden SSH Configuration
Edit /etc/ssh/sshd_config:
sudo tee /etc/ssh/sshd_config.d/hardening.conf > /dev/null << 'EOF'
Port 2222
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
MaxAuthTries 3
LoginGraceTime 20
X11Forwarding no
AllowTcpForwarding no
ClientAliveInterval 300
ClientAliveCountMax 2
AllowUsers deploy
EOF
sudo systemctl restart sshd
Key changes:
- Non-standard port reduces drive-by scanning noise
- Root login disabled forces use of sudo
- Password auth disabled eliminates brute-force attacks
AllowUsersrestricts SSH to named accounts only
4. Configure UFW Firewall
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 2222/tcp comment "SSH"
sudo ufw allow 80/tcp comment "HTTP"
sudo ufw allow 443/tcp comment "HTTPS"
sudo ufw enable
sudo ufw status verbose
5. Install and Configure Fail2ban
Fail2ban monitors log files and bans IPs that show malicious behavior:
sudo apt install -y fail2ban
sudo tee /etc/fail2ban/jail.local > /dev/null << 'EOF'
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 3
banaction = ufw
[sshd]
enabled = true
port = 2222
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
EOF
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd
6. Enable Unattended Security Upgrades
sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
Verify the configuration:
sudo tee /etc/apt/apt.conf.d/50unattended-upgrades > /dev/null << 'EOF'
Unattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}-security";
"${distro_id}ESMApps:${distro_codename}-apps-security";
};
Unattended-Upgrade::AutoFixInterruptedDpkg "true";
Unattended-Upgrade::Remove-Unused-Dependencies "true";
Unattended-Upgrade::Automatic-Reboot "false";
Unattended-Upgrade::Mail "admin@example.com";
EOF
7. Kernel Hardening with sysctl
sudo tee /etc/sysctl.d/99-hardening.conf > /dev/null << 'EOF'
# Disable IP forwarding
net.ipv4.ip_forward = 0
# Disable ICMP redirects
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
# Enable SYN flood protection
net.ipv4.tcp_syncookies = 1
# Disable source routing
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
# Log Martian packets
net.ipv4.conf.all.log_martians = 1
# Restrict kernel pointer exposure
kernel.kptr_restrict = 2
# Restrict dmesg access
kernel.dmesg_restrict = 1
# Restrict unprivileged BPF
kernel.unprivileged_bpf_disabled = 1
EOF
sudo sysctl --system
8. Enable Audit Logging with auditd
sudo apt install -y auditd audispd-plugins
# Watch for changes to critical files
sudo tee /etc/audit/rules.d/hardening.rules > /dev/null << 'EOF'
# Monitor SSH config changes
-w /etc/ssh/sshd_config -p wa -k sshd_config
# Monitor user/group changes
-w /etc/passwd -p wa -k passwd_changes
-w /etc/shadow -p wa -k shadow_changes
-w /etc/group -p wa -k group_changes
# Monitor sudo usage
-w /etc/sudoers -p wa -k sudoers
-w /etc/sudoers.d/ -p wa -k sudoers_d
# Monitor cron
-w /etc/crontab -p wa -k cron
-w /var/spool/cron/ -p wa -k cron
# Log all commands run by root
-a always,exit -F arch=b64 -F euid=0 -S execve -k root_commands
EOF
sudo systemctl enable --now auditd
sudo auditctl -l
9. Disable Unnecessary Services
# List all running services
systemctl list-units --type=service --state=running
# Disable services we do not need
sudo systemctl disable --now snapd
sudo systemctl disable --now cups
sudo systemctl disable --now avahi-daemon
10. CIS Benchmark Quick Checks
The Center for Internet Security publishes comprehensive benchmarks for Ubuntu. Here are the most impactful items:
# Verify filesystem permissions
stat -c "%a %n" /etc/passwd # Should be 644
stat -c "%a %n" /etc/shadow # Should be 640
stat -c "%a %n" /etc/group # Should be 644
# Ensure no world-writable files exist in system dirs
find /usr -xdev -type f -perm -0002 -ls
# Check for empty password fields
sudo awk -F: '($2 == "") { print $1 }' /etc/shadow
# Ensure root is the only UID 0 account
awk -F: '($3 == 0) { print $1 }' /etc/passwd
Server hardening is not a one-time task. We should revisit this checklist after every major system upgrade and audit our configurations regularly. Automating these checks with tools like Lynis or OpenSCAP ensures that configuration drift does not silently undo our hardening work. A hardened server is the foundation on which everything else depends.
Or read how we handle it in Security & Compliance.
Related Articles
Hardening A Fresh Ubuntu 24.04 VPS In 15 Minutes
A fresh public Ubuntu 24.04 VPS sees SSH brute-force attempts within a minute of getting an IP. The 15-minute hardening run that closes the obvious doors before production traffic, with the verification commands.
Server & DevOpsHow to Set Up Automated Server Backups with Restic and S3 on Ubuntu
A complete walkthrough for setting up encrypted, deduplicated server backups with Restic and S3-compatible storage on Ubuntu, including systemd timers, verification, and restore procedures.
LaravelMastering Laravel Workers: A Step-by-Step Guide to Setting Up a Laravel Worker Server on Ubuntu
A comprehensive guide to setting up Laravel queue workers on Ubuntu, covering Redis configuration, job creation, Supervisor process management, Horizon monitoring, scaling, and troubleshooting.