How to Harden a Linux Server: The Practitioner Security Checklist

Retool's new app builder is where AI-generated code ships safely
Building apps with AI is easy. Getting them to production safely is another story.
A default Linux installation is designed for compatibility and ease of use, not security. Root SSH login is typically enabled, all inbound ports are open, no audit logging is configured, and system services you may not need are running. Each of these is an attack vector.
This checklist covers the twenty most impactful hardening changes for Ubuntu and RHEL-family systems: prioritized by attack surface reduction, with commands that can be applied immediately.
SSH Hardening (Highest Priority)
SSH is the primary remote administration vector and the most targeted service on internet-facing Linux servers. Eight changes reduce SSH attack surface significantly.
Edit /etc/ssh/sshd_config:
sudo nano /etc/ssh/sshd_config
Apply these settings:
# 1. Disable root login: require elevation via sudo after logging in as a named user
PermitRootLogin no
# 2. Disable password authentication: require SSH key authentication
PasswordAuthentication no
PubkeyAuthentication yes
# 3. Disable empty passwords
PermitEmptyPasswords no
# 4. Restrict SSH to specific users or groups (edit to match your user list)
AllowUsers alice bob deployuser
# OR restrict by group:
AllowGroups sshusers
# 5. Set a login grace time (disconnect if not authenticated within 30 seconds)
LoginGraceTime 30
# 6. Limit authentication attempts per connection
MaxAuthTries 3
# 7. Disable X11 forwarding (not needed for server administration)
X11Forwarding no
# 8. Disable agent forwarding unless explicitly required
AllowAgentForwarding no
# 9. Set idle session timeout (disconnect after 5 minutes idle)
ClientAliveInterval 300
ClientAliveCountMax 1
# 10. Use only strong key exchange algorithms
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512
Ciphers aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com
MACs hmac-sha2-256,hmac-sha2-512,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com
Restart SSH (keep your current session open; verify from a second connection):
sudo sshd -t # Test config for syntax errors first
sudo systemctl restart sshd
User and Privilege Management
11. Disable or lock unused system accounts:
# List users with login shells
grep -v '/nologin\|/false' /etc/passwd
# Lock accounts that should not be able to log in
sudo passwd -l username
# Set no-login shell for service accounts
sudo usermod -s /usr/sbin/nologin serviceaccount
12. Set strong password policy:
# Ubuntu/Debian
sudo apt-get install -y libpam-pwquality
sudo nano /etc/security/pwquality.conf
# Add or modify:
minlen = 12
minclass = 3
maxrepeat = 3
# Set password expiry (90-day maximum, warn at 14 days)
sudo chage -M 90 -W 14 username
13. Configure sudo to log all commands:
sudo visudo
# Add at the bottom:
Defaults logfile="/var/log/sudo.log"
Defaults log_input, log_output
14. Review and restrict sudo access:
# List all users with sudo access
sudo grep -r 'ALL=(ALL)' /etc/sudoers /etc/sudoers.d/
# Use NOPASSWD sparingly: only for specific commands that automation requires
# BAD: deployuser ALL=(ALL) NOPASSWD:ALL
# GOOD: deployuser ALL=(ALL) NOPASSWD:/usr/bin/systemctl restart myapp
Briefings like this, every morning before 9am.
Threat intel, active CVEs, and campaign alerts, distilled for practitioners. 50,000+ subscribers. No noise.
Service Minimization and Firewall
15. Disable and remove unnecessary services:
# List all running services
systemctl list-units --type=service --state=running
# Disable services not needed (examples: adjust for your use case)
sudo systemctl disable --now avahi-daemon # mDNS: not needed on servers
sudo systemctl disable --now cups # Printing: not needed on servers
sudo systemctl disable --now bluetooth # Bluetooth: not on VMs/servers
# Remove packages not needed
# Ubuntu:
sudo apt-get remove --purge telnet rsh-client rsh-redone-client ftp
# RHEL:
sudo dnf remove telnet rsh ftp
16. Configure UFW (Ubuntu) or firewalld (RHEL): allow only needed ports:
# Ubuntu: UFW
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow from 10.0.1.0/24 to any port 22 # SSH from trusted subnet only
sudo ufw allow 443/tcp # HTTPS if this is a web server
sudo ufw enable
sudo ufw status verbose
# RHEL: firewalld
sudo firewall-cmd --set-default-zone=drop
sudo firewall-cmd --zone=trusted --add-source=10.0.1.0/24 --permanent
sudo firewall-cmd --zone=trusted --add-service=ssh --permanent
sudo firewall-cmd --reload
17. Enable automatic security updates:
# Ubuntu
sudo apt-get install -y unattended-upgrades
sudo dpkg-reconfigure unattended-upgrades # Select 'Yes'
# Verify configuration
cat /etc/apt/apt.conf.d/50unattended-upgrades | grep -v '^//' | grep -v '^$'
# RHEL
sudo dnf install -y dnf-automatic
sudo nano /etc/dnf/automatic.conf
# Set: apply_updates = yes
# Set: upgrade_type = security
sudo systemctl enable --now dnf-automatic.timer
Kernel Hardening and Audit Logging
18. Apply kernel security parameters via sysctl:
sudo nano /etc/sysctl.d/99-hardening.conf
Add:
# Disable IP source routing
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
# Enable SYN cookie protection (protects against SYN flood)
net.ipv4.tcp_syncookies = 1
# Disable ICMP redirects (prevents routing manipulation)
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
# Log suspicious martian packets
net.ipv4.conf.all.log_martians = 1
# Disable core dumps (prevents memory disclosure from crashed processes)
fs.suid_dumpable = 0
kernel.core_pattern = |/bin/false
# Restrict ptrace to privileged processes (prevents process memory reading)
kernel.yama.ptrace_scope = 1
# Restrict kernel log access to root
kernel.dmesg_restrict = 1
Apply:
sudo sysctl -p /etc/sysctl.d/99-hardening.conf
19. Enable auditd for security event logging:
# Install
sudo apt-get install -y auditd audispd-plugins # Ubuntu
sudo dnf install -y audit # RHEL
# Add audit rules
sudo nano /etc/audit/rules.d/hardening.rules
Add:
# Monitor authentication events
-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
# Monitor SSH configuration
-w /etc/ssh/sshd_config -p wa -k sshd
# Monitor cron
-w /etc/cron.d -p wa -k cron
-w /var/spool/cron -p wa -k cron
# Log privilege escalation
-a always,exit -F arch=b64 -S execve -F euid=0 -F auid!=4294967295 -k root_commands
sudo systemctl enable --now auditd
sudo auditctl -l # Verify rules are loaded
20. Run lynis for a baseline audit score:
# Install lynis
sudo apt-get install -y lynis # Ubuntu
sudo dnf install -y lynis # RHEL (from EPEL)
# Run full audit
sudo lynis audit system
# Lynis produces a hardening index score (0-100)
# Score interpretation: < 60 poor, 60-75 moderate, > 75 good
# Review the 'Suggestions' and 'Warnings' sections for remaining items
The bottom line
Linux server hardening follows a priority order: SSH configuration first (disable root login, disable password auth, restrict to allowed users, set timeouts), then user privilege management (lock unused accounts, configure sudo logging), then service minimization and host firewall, then kernel sysctl parameters and auditd logging. Run lynis after implementing these changes to get a baseline score and identify remaining gaps. Aim for a lynis hardening index above 75 before exposing a server to the internet.
Frequently asked questions
What are the most important Linux server hardening steps?
In priority order: disable SSH root login and password authentication (require key-only), restrict SSH to specific users, set SSH idle timeouts, lock unused system accounts, enable host firewall (UFW or firewalld) with default-deny inbound, enable automatic security updates, apply kernel hardening sysctl parameters, and enable auditd for security event logging.
How do I audit my Linux server security configuration?
Install and run lynis ('sudo lynis audit system'): it evaluates your configuration against security benchmarks and produces a hardening index score with specific recommendations. For compliance-driven environments, use the CIS Benchmark for your distribution or the DISA STIG for RHEL: both are available as automated check scripts.
What is the most important Linux server hardening step?
Disabling password-based SSH authentication and requiring key-based authentication is the single highest-impact hardening step. Password authentication exposes servers to brute force and credential stuffing attacks from the internet: SSH honeypots receive thousands of login attempts per hour. Set 'PasswordAuthentication no' and 'PermitRootLogin no' in /etc/ssh/sshd_config and restart sshd. Verify you have a working key-based session before closing your current session or you will lock yourself out.
How do I configure automatic security updates on Linux?
For Ubuntu/Debian: install 'unattended-upgrades' and configure /etc/apt/apt.conf.d/50unattended-upgrades to enable automatic installation of security updates only (not all package updates). Set up email notifications on upgrade failures. For RHEL/CentOS: install 'dnf-automatic' and configure /etc/dnf/automatic.conf with 'upgrade_type = security' and 'apply_updates = yes'. For both: configure automatic reboots only outside business hours (weekend nights) since kernel updates require reboots. Test automatic updates in a non-production environment first to verify applications survive package updates without manual intervention.
How do I set up auditd on Linux to detect suspicious activity?
Auditd is the Linux kernel audit daemon that logs system calls and file access to /var/log/audit/audit.log. Essential rules to configure in /etc/audit/rules.d/: monitor writes to /etc/passwd, /etc/shadow, /etc/sudoers (privilege escalation paths); log all privileged command executions (setuid/setgid); monitor modifications to /etc/ssh/sshd_config and authorized_keys files; log use of 'chmod' with setuid bit; monitor kernel module loads with auditctl -w /sbin/insmod. Forward audit logs to your SIEM immediately: local audit logs on a compromised server may be tampered with. The aureport utility generates summary reports from audit logs for quick review.
How do you validate that Linux hardening changes have been applied correctly across a fleet?
Manual spot-checking after applying hardening changes does not scale beyond a handful of servers, and configuration drift erodes your hardening baseline over time. Use three approaches in combination. First, run lynis as a scheduled job across your fleet and export the hardening index score for each host to your monitoring system. A score drop of more than five points on any host is an alert condition: something changed. Second, use configuration management tools (Ansible, Chef, Puppet, or SaltStack) to enforce hardening settings continuously rather than applying them once. Write your hardening steps as idempotent tasks that check the current state and apply the required setting if it has drifted. Run these playbooks on a weekly schedule: configuration drift is caught and corrected automatically without manual intervention. Third, for compliance-driven environments, use the CIS Benchmarks' provided audit scripts: CIS publishes platform-specific scripts that check each benchmark control and report pass/fail. These produce structured output that feeds into compliance dashboards. For cloud environments, use AWS Config rules or Azure Policy to evaluate instance configuration against your hardening baseline: any non-compliant instance triggers a remediation or an alert depending on your policy mode. The combination of continuous enforcement through configuration management and regular auditing with lynis or CIS scripts ensures that hardening is a maintained state rather than a one-time deployment event.
Sources & references
Free resources
Critical CVE Reference Card 2025–2026
25 actively exploited vulnerabilities with CVSS scores, exploit status, and patch availability. Print it, pin it, share it with your SOC team.
Ransomware Incident Response Playbook
Step-by-step 24-hour IR checklist covering detection, containment, eradication, and recovery. Built for SOC teams, IR leads, and CISOs.
Get threat intel before your inbox does.
50,000+ security professionals read Decryption Digest for early warnings on zero-days, ransomware, and nation-state campaigns. Free, daily, no spam.
Unsubscribe anytime. We never sell your data.

Founder & Cybersecurity Evangelist, Decryption Digest
Cybersecurity professional with expertise in threat intelligence, vulnerability research, and enterprise security. Covers zero-days, ransomware, and nation-state operations for 50,000+ security professionals every morning.
Win a $2,495 Black Hat pass.
Full-access to Black Hat USA 2026 in Las Vegas. Subscribe free to enter.
