Linux Security Hardening: A Practical Checklist
A default Linux installation is not production-ready. Walk through SSH hardening, firewall setup, automatic updates, and user privilege controls step by step.
Table of Contents
- Why Default Installations Are Insecure
- User Account and Authentication Hardening
- Disable Root Login and Use Sudo
- Enforce Strong Password Policies
- Lock Unused Accounts
- SSH Hardening
- Firewall Configuration
- System Updates and Package Management
- Disabling Unnecessary Services
- File System Security
- Intrusion Detection and Monitoring
- Kernel Hardening with sysctl
Why Default Installations Are Insecure
A freshly installed Linux server ships with a set of defaults optimized for broad compatibility and ease of setup — not security. Services you don't need may be running, SSH accepts password authentication (vulnerable to brute force), the firewall may be permissive or disabled, and user accounts may have excessive privileges. Hardening is the process of systematically reducing the attack surface to match your actual requirements.
This checklist targets Debian/Ubuntu and RHEL/CentOS families, but the principles apply universally.
User Account and Authentication Hardening
Disable Root Login and Use Sudo
Never log in as root directly. Create a dedicated admin user and grant it sudo privileges:
adduser adminuser
usermod -aG sudo adminuser # Debian/Ubuntu
usermod -aG wheel adminuser # RHEL/CentOS
Disable root SSH login in /etc/ssh/sshd_config: set PermitRootLogin no.
Enforce Strong Password Policies
Install libpam-pwquality (Debian) or pam_pwquality (RHEL) and configure minimum length, complexity requirements, and history in /etc/security/pwquality.conf. Set password aging in /etc/login.defs: PASS_MAX_DAYS 90, PASS_MIN_DAYS 1, PASS_WARN_AGE 14.
Lock Unused Accounts
passwd -l username # Lock an account
chage -E 0 username # Expire immediately
Audit accounts with no password or with shell access that shouldn't have it (grep -v 'nologin\|false' /etc/passwd).
SSH Hardening
SSH is the most common remote access vector. Harden /etc/ssh/sshd_config:
Port 2222 # Non-default port reduces automated scans
PermitRootLogin no
PasswordAuthentication no # Key-based auth only
PubkeyAuthentication yes
AllowUsers adminuser # Whitelist specific users
MaxAuthTries 3
ClientAliveInterval 300
ClientAliveCountMax 2
X11Forwarding no
AllowTcpForwarding no # Unless needed
Protocol 2
After changing the port, update your firewall rules before restarting sshd. Use sshd -t to test the configuration for syntax errors.
For key generation, prefer Ed25519 over RSA 2048:
ssh-keygen -t ed25519 -C "admin@server"
Firewall Configuration
UFW (Ubuntu/Debian)
ufw default deny incoming
ufw default allow outgoing
ufw allow 2222/tcp # Your SSH port
ufw allow 443/tcp # HTTPS if web server
ufw enable
ufw status verbose
firewalld (RHEL/CentOS)
firewall-cmd --set-default-zone=drop
firewall-cmd --permanent --add-port=2222/tcp
firewall-cmd --reload
Use nftables directly for maximum control and performance on modern kernels. Apply the principle of default deny — allow only what is explicitly needed.
System Updates and Package Management
Keep the system patched. Unpatched vulnerabilities are the most common initial access vector after credential attacks:
# Debian/Ubuntu — enable unattended security upgrades
apt install unattended-upgrades
dpkg-reconfigure unattended-upgrades
# RHEL/CentOS — enable automatic updates
dnf install dnf-automatic
systemctl enable --now dnf-automatic.timer
Remove packages you don't need: apt purge telnet rsh-server ypserv xinetd. Each installed package is a potential vulnerability.
Disabling Unnecessary Services
List all running services and disable what you don't use:
systemctl list-units --type=service --state=running
systemctl disable --now servicename
Common candidates for removal on a web server: avahi-daemon, cups, bluetooth, rpcbind. Every open port is a potential entry point.
File System Security
- Set sticky bit on world-writable directories:
chmod +t /tmp - Use
noexec,nosuid,nodevmount options for/tmp,/var/tmp, and removable media in/etc/fstab - Audit SUID/SGID binaries:
find / -perm /6000 -type f 2>/dev/null— remove the bit from anything that doesn't require it - Restrict
/etc/cron*permissions:chmod 700 /etc/cron.d /etc/cron.daily
Intrusion Detection and Monitoring
- Fail2ban: automatically bans IPs with repeated authentication failures — essential for any internet-facing SSH
- auditd: kernel-level logging of system calls, file access, and user commands — feeds SIEMs with rich event data
- AIDE (Advanced Intrusion Detection Environment): creates a cryptographic database of file hashes at a known-good state and alerts on changes
- Logwatch or GoAccess: regular log summaries sent by email
Centralize logs to a remote syslog server or SIEM immediately — if an attacker achieves root they will clear local logs.
Kernel Hardening with sysctl
Add to /etc/sysctl.d/99-hardening.conf:
net.ipv4.ip_forward = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.tcp_syncookies = 1
kernel.randomize_va_space = 2
kernel.dmesg_restrict = 1
fs.protected_hardlinks = 1
fs.protected_symlinks = 1
Apply with sysctl --system. These settings disable IP forwarding, prevent ICMP redirect attacks, enable SYN cookie protection, and enforce ASLR.