Linux Server Hardening Checklist¶
When I set up a fresh Linux server, there's a standard set of things I do before I put anything on it. None of this is exotic — it's the basics that prevent the most common attacks. Do these before the server touches the public internet.
The Short Answer¶
New server checklist: create a non-root user, disable root SSH login, use key-based auth only, configure a firewall, keep packages updated. That covers 90% of what matters.
1. Create a Non-Root User¶
Don't work as root. Create a user, give it sudo:
# Create user
adduser yourname
# Add to sudo group (Debian/Ubuntu)
usermod -aG sudo yourname
# Add to wheel group (Fedora/RHEL)
usermod -aG wheel yourname
Log out and log back in as that user before doing anything else.
2. SSH Key Authentication¶
Passwords over SSH are a liability. Set up key-based auth and disable password login.
On your local machine, generate a key if you don't have one:
Copy the public key to the server:
Or manually append your public key to ~/.ssh/authorized_keys on the server.
Test that key auth works before disabling passwords.
3. Harden sshd_config¶
Edit /etc/ssh/sshd_config:
# Disable root login
PermitRootLogin no
# Disable password authentication
PasswordAuthentication no
# Disable empty passwords
PermitEmptyPasswords no
# Limit to specific users (optional but good)
AllowUsers yourname
# Change the port (optional — reduces log noise, not real security)
Port 2222
Restart SSH after changes:
Keep your current session open when testing — if you lock yourself out you'll need console access to fix it.
4. Configure a Firewall¶
ufw (Ubuntu/Debian):
sudo apt install ufw
# Default: deny incoming, allow outgoing
sudo ufw default deny incoming
sudo ufw default allow outgoing
# Allow SSH (use your actual port if you changed it)
sudo ufw allow 22/tcp
# Allow whatever services you're running
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# Enable
sudo ufw enable
# Check status
sudo ufw status verbose
firewalld (Fedora/RHEL):
sudo systemctl enable --now firewalld
# Allow SSH
sudo firewall-cmd --permanent --add-service=ssh
# Allow HTTP/HTTPS
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
# Apply changes
sudo firewall-cmd --reload
# Check
sudo firewall-cmd --list-all
5. Keep Packages Updated¶
Security patches come through package updates. Automate this or do it regularly:
# Ubuntu/Debian — manual
sudo apt update && sudo apt upgrade
# Enable unattended security upgrades (Ubuntu)
sudo apt install unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades
# Fedora/RHEL — manual
sudo dnf upgrade
# Enable automatic updates (Fedora)
sudo dnf install dnf-automatic
sudo systemctl enable --now dnf-automatic.timer
6. Fail2ban¶
Fail2ban watches log files and bans IPs that fail authentication too many times. Helps with brute force noise.
# Ubuntu/Debian
sudo apt install fail2ban
# Fedora/RHEL
sudo dnf install fail2ban
# Start and enable
sudo systemctl enable --now fail2ban
Create /etc/fail2ban/jail.local to override defaults:
7. Disable Unnecessary Services¶
Less running means less attack surface:
# See what's running
systemctl list-units --type=service --state=active
# Disable something you don't need
sudo systemctl disable --now servicename
Common ones to disable on a dedicated server: avahi-daemon, cups, bluetooth.
Gotchas & Notes¶
- Don't lock yourself out. Test SSH key auth in a second terminal before disabling passwords. Keep the original session open.
- If you changed the SSH port, make sure the firewall allows the new port before restarting sshd. Block the old port after you've confirmed the new one works.
- fail2ban and Docker don't always play nicely. Docker bypasses iptables rules in some configurations. If you're running services in Docker, test that fail2ban is actually seeing traffic.
- SELinux on RHEL/Fedora may block things your firewall allows. Check
ausearch -m avcif a service stops working after hardening. - This is a baseline, not a complete security posture. For anything holding sensitive data, also look at: disk encryption, intrusion detection (AIDE, Tripwire), log shipping to a separate system, and regular audits.
See Also¶
- [[managing-linux-services-systemd-ansible]]
- [[debugging-broken-docker-containers]]