Server security hardening is the systematic process of reducing your server's attack surface by eliminating unnecessary services, tightening access controls, and implementing defense-in-depth strategies. Every unhardened server exposes your infrastructure to brute-force attacks, privilege escalation, and data breaches. This checklist gives you a deployable protocol to secure Linux servers against common attack vectors.
Pre-Hardening Assessment
Before making changes, document your current state. Run a baseline security audit to understand what you're working with.
Inventory Current Services
List all running services and open ports:
sudo systemctl list-units --type=service --state=running
sudo ss -tulpn
sudo netstat -tulpn
Identify services you don't recognize or need. Every running service is a potential entry point.
Check Installed Packages
Review installed software for unnecessary packages:
# Debian/Ubuntu
dpkg --get-selections | grep -v deinstall
# RHEL/CentOS/AlmaLinux
rpm -qa
Remove compilers, development tools, and legacy software from production systems unless specifically required.
Document User Accounts
List all user accounts with login shells:
cat /etc/passwd | grep -v nologin | grep -v false
sudo lastlog
Every user account is a potential compromise vector. Remove unused accounts immediately.
SSH Hardening
SSH is the primary remote access vector and the most frequently attacked service on internet-facing servers.
Disable Root Login
Edit /etc/ssh/sshd_config:
PermitRootLogin no
Force all administrators to use sudo instead of logging in directly as root. This creates an audit trail.
Use Key-Based Authentication Only
Disable password authentication entirely:
PasswordAuthentication no
ChallengeResponseAuthentication no
PubkeyAuthentication yes
Generate and deploy SSH keys for all administrators before disabling passwords. Test key authentication thoroughly before applying this change.
Change Default SSH Port
While not true security, changing the default port reduces automated scanning noise:
Port 2849
Update your firewall rules to match the new port. Remember to test connectivity before closing your current session.
Restrict SSH Access by User and IP
Limit which users can SSH and from which networks:
AllowUsers [email protected]/24 [email protected]/8
PermitEmptyPasswords no
MaxAuthTries 3
MaxSessions 2
Enable SSH Protocol 2 Only
SSH protocol 1 has known vulnerabilities:
Protocol 2
Modern systems default to protocol 2, but verify explicitly.
Apply Changes
After editing sshd_config, validate and restart:
sudo sshd -t
sudo systemctl restart sshd
Keep your current session open and test new connections in a separate terminal before closing.
Firewall Configuration
A properly configured firewall blocks unauthorized access at the network layer before services can be exploited.
Configure iptables or firewalld
For systems using iptables:
# Default deny policy
sudo iptables -P INPUT DROP
sudo iptables -P FORWARD DROP
sudo iptables -P OUTPUT ACCEPT
# Allow established connections
sudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# Allow localhost
sudo iptables -A INPUT -i lo -j ACCEPT
# Allow SSH (adjust port as needed)
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT
# Allow HTTP/HTTPS
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT
# Save rules
sudo iptables-save > /etc/iptables/rules.v4
For firewalld:
sudo firewall-cmd --set-default-zone=drop
sudo firewall-cmd --zone=drop --add-service=ssh --permanent
sudo firewall-cmd --zone=drop --add-service=http --permanent
sudo firewall-cmd --zone=drop --add-service=https --permanent
sudo firewall-cmd --reload
Implement Rate Limiting
Protect against brute-force attacks:
# Limit SSH connections
sudo iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --set
sudo iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 60 --hitcount 4 -j DROP
This allows three connection attempts per minute per IP address.
User Account Management
Compromised user accounts are the most common initial access vector in server breaches.
Enforce Strong Password Policy
Install and configure PAM modules:
sudo apt install libpam-pwquality # Debian/Ubuntu
sudo yum install libpwquality # RHEL/CentOS
Edit /etc/security/pwquality.conf:
minlen = 14
dcredit = -1
ucredit = -1
ocredit = -1
lcredit = -1
Implement Account Lockout
Configure automatic lockout after failed attempts in /etc/pam.d/common-auth or /etc/pam.d/system-auth:
auth required pam_faillock.so preauth silent audit deny=5 unlock_time=900
auth [default=die] pam_faillock.so authfail audit deny=5 unlock_time=900
Remove or Lock Unused Accounts
# Lock account
sudo usermod -L username
# Set shell to nologin
sudo usermod -s /usr/sbin/nologin username
# Or remove entirely
sudo userdel -r username
Configure sudo Properly
Edit /etc/sudoers using visudo:
Defaults timestamp_timeout=5
Defaults passwd_tries=3
Defaults logfile="/var/log/sudo.log"
Grant minimal necessary privileges. Avoid blanket ALL=(ALL) ALL permissions.
System Updates and Patch Management
Unpatched vulnerabilities are the easiest attack vector to exploit and the easiest to prevent.
Enable Automatic Security Updates
For Debian/Ubuntu:
sudo apt install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
Edit /etc/apt/apt.conf.d/50unattended-upgrades to configure update behavior.
For RHEL/CentOS:
sudo yum install yum-cron
sudo systemctl enable yum-cron
sudo systemctl start yum-cron
Regular Manual Updates
Even with automatic updates enabled, schedule regular manual update reviews:
# Debian/Ubuntu
sudo apt update && sudo apt upgrade -y
# RHEL/CentOS
sudo yum update -y
Reboot after kernel updates to apply changes.
Service Hardening
Disable Unnecessary Services
Stop and disable services you don't need:
sudo systemctl disable cups
sudo systemctl stop cups
sudo systemctl disable avahi-daemon
sudo systemctl stop avahi-daemon
Common candidates for disabling: printing services, Bluetooth, graphical targets, legacy protocols.
Secure Web Server Configuration
For Apache, edit /etc/apache2/conf-available/security.conf:
ServerTokens Prod
ServerSignature Off
TraceEnable Off
For Nginx, edit /etc/nginx/nginx.conf:
server_tokens off;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
Database Security
For MySQL/MariaDB:
sudo mysql_secure_installation
This script removes anonymous users, disallows remote root login, and removes test databases. Additionally, bind MySQL to localhost only in /etc/mysql/my.cnf:
[mysqld]
bind-address = 127.0.0.1
File System Hardening
Set Proper File Permissions
Critical system files should not be world-readable:
sudo chmod 600 /etc/ssh/sshd_config
sudo chmod 600 /boot/grub/grub.cfg
sudo chmod 644 /etc/passwd
sudo chmod 600 /etc/shadow
Configure Secure Mount Options
Edit /etc/fstab to add security options:
/tmp /tmp tmpfs defaults,noexec,nosuid,nodev 0 0
/var/tmp /var/tmp tmpfs defaults,noexec,nosuid,nodev 0 0
These options prevent execution of binaries from temporary directories, a common malware tactic.
Enable File System Auditing
Install and configure auditd:
sudo apt install auditd # Debian/Ubuntu
sudo yum install audit # RHEL/CentOS
sudo systemctl enable auditd
sudo systemctl start auditd
Add audit rules in /etc/audit/rules.d/audit.rules:
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/sudoers -p wa -k actions
-w /var/log/sudo.log -p wa -k actions
Intrusion Detection and Monitoring
Install Fail2Ban
Fail2ban monitors log files and bans IPs showing malicious behavior:
sudo apt install fail2ban # Debian/Ubuntu
sudo yum install fail2ban # RHEL/CentOS
Configure /etc/fail2ban/jail.local:
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 5
[sshd]
enabled = true
port = 22
logpath = /var/log/auth.log
Configure System Logging
Ensure rsyslog or systemd-journald is capturing security events:
sudo systemctl enable rsyslog
sudo systemctl start rsyslog
Centralize logs to a remote syslog server when possible. Attackers often delete local logs.
Install AIDE or Tripwire
File integrity monitoring detects unauthorized changes:
sudo apt install aide
sudo aideinit
sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db
Schedule regular checks:
sudo aide --check
Kernel Hardening
Configure sysctl Security Parameters
Edit /etc/sysctl.conf or create /etc/sysctl.d/99-security.conf:
# IP forwarding
net.ipv4.ip_forward = 0
# Syn flood protection
net.ipv4.tcp_syncookies = 1
# Ignore ICMP redirects
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
# 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 IPv6 if not needed
net.ipv6.conf.all.disable_ipv6 = 1
Apply changes:
sudo sysctl -p
Backup and Recovery
Hardening is worthless if you can't recover from a compromise or system failure.
Implement Regular Backups
Schedule automated backups of critical data and configuration:
# Example backup script
#!/bin/bash
tar -czf /backup/etc-$(date +%Y%m%d).tar.gz /etc
tar -czf /backup/home-$(date +%Y%m%d).tar.gz /home
Store backups off-server. An attacker with root access can delete local backups.
Test Recovery Procedures
Regularly verify that your backups can be restored. Untested backups are not backups.
Post-Hardening Validation
Run Security Scanners
Scan your hardened server from external networks:
# From another system
nmap -sS -sV -O target-server-ip
Verify that only intended ports are open and services are properly configured.
Review Logs
Check for configuration errors:
sudo grep -i error /var/log/syslog
sudo journalctl -p err -b
Vulnerability Assessment
Run vulnerability scanners to identify remaining weaknesses. OpenVAS and Lynis are popular open-source options:
sudo lynis audit system
Maintenance and Continuous Hardening
Server hardening is not a one-time task. Schedule regular reviews:
- Weekly: Review authentication logs and failed login attempts
- Monthly: Check for available security updates and patches
- Quarterly: Re-run vulnerability scans and update hardening based on new threats
- Annually: Complete audit of all user accounts, services, and firewall rules
Document all changes in a change log. When troubleshooting issues, your hardening configuration is the first place to look.
Conclusion
Server security hardening closes the gaps attackers exploit most frequently. This checklist covers the essential steps every Linux server needs: SSH hardening eliminates weak authentication, firewall rules block unauthorized access, regular updates patch known vulnerabilities, and monitoring detects intrusion attempts. Implement these controls systematically rather than all at once, testing each change before moving to the next. Security is a process, not a destination. Schedule regular reviews to adapt your hardening protocol as threats evolve. A hardened server is not invulnerable, but it raises the cost of attack high enough to deter most threat actors.
