Linux Server Hardening: Complete Guide
Introduction
Linux server hardening is the critical process of securing a Linux system by reducing its attack surface and implementing multiple layers of security controls. In today's threat landscape, where cyberattacks are increasingly sophisticated and automated, a properly hardened server can mean the difference between business continuity and catastrophic data breaches.
This comprehensive guide provides system administrators, DevOps engineers, and security professionals with a systematic approach to hardening Linux servers. Whether you're managing a single VPS or an enterprise infrastructure, implementing these security measures will significantly reduce your risk exposure and ensure compliance with industry security standards.
Server hardening isn't a one-time task but an ongoing process that requires regular assessment, updates, and adaptation to emerging threats. This guide follows defense-in-depth principles, implementing multiple security layers so that if one control fails, others remain in place to protect your systems.
Understanding the Threat Landscape
Common Attack Vectors
Modern Linux servers face numerous threats from multiple sources:
Brute Force Attacks: Automated bots continuously scan the internet attempting to gain SSH access through password guessing. These attacks can generate thousands of login attempts per day against exposed servers.
Vulnerability Exploitation: Unpatched software vulnerabilities remain one of the primary attack vectors. Attackers actively scan for systems running outdated software with known exploits.
Privilege Escalation: Once attackers gain limited access, they attempt to exploit misconfigurations or kernel vulnerabilities to obtain root privileges.
Malware and Rootkits: Advanced persistent threats deploy sophisticated malware designed to maintain long-term access while evading detection.
DDoS Attacks: Distributed denial-of-service attacks can overwhelm server resources, making services unavailable to legitimate users.
Supply Chain Attacks: Compromised software packages or dependencies can introduce vulnerabilities directly into your infrastructure.
Risk Assessment
Before implementing hardening measures, understand your specific risk profile:
- Data Sensitivity: What type of data does your server process or store?
- Compliance Requirements: What regulatory frameworks apply to your operations?
- Service Availability: What is the acceptable downtime threshold?
- Resource Constraints: What security tools can your server performance support?
- Attack Surface: What services are exposed to the internet?
Pre-Hardening Preparation
System Inventory
Document your current server configuration before making changes:
# System information
hostnamectl
uname -a
cat /etc/os-release
# Network configuration
ip addr show
ip route show
ss -tuln
# Installed services
systemctl list-unit-files --type=service --state=enabled
Backup Critical Configuration
Always backup configuration files before modification:
# Create backup directory
sudo mkdir -p /root/config-backup-$(date +%Y%m%d)
# Backup critical files
sudo cp -r /etc/ssh /root/config-backup-$(date +%Y%m%d)/
sudo cp -r /etc/sysctl.conf /root/config-backup-$(date +%Y%m%d)/
sudo cp -r /etc/security /root/config-backup-$(date +%Y%m%d)/
Operating System Hardening
Minimal Installation
Start with a minimal OS installation containing only essential packages:
# Ubuntu/Debian - Remove unnecessary packages
sudo apt-get autoremove
sudo apt-get purge $(dpkg -l | grep '^rc' | awk '{print $2}')
# CentOS/Rocky Linux - List installed packages
sudo dnf list installed
sudo dnf remove package-name
System Updates and Patch Management
Maintaining current security patches is critical:
# Ubuntu/Debian
sudo apt-get update
sudo apt-get upgrade -y
sudo apt-get dist-upgrade -y
# Enable automatic security updates
sudo apt-get install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
Configure automatic updates on CentOS/Rocky:
# CentOS/Rocky Linux
sudo dnf update -y
sudo dnf install dnf-automatic
sudo systemctl enable --now dnf-automatic.timer
Edit /etc/dnf/automatic.conf:
[commands]
upgrade_type = security
apply_updates = yes
Kernel Hardening with Sysctl
Kernel parameters provide powerful security controls:
Edit /etc/sysctl.conf or create /etc/sysctl.d/99-hardening.conf:
# IP Forwarding
net.ipv4.ip_forward = 0
net.ipv6.conf.all.forwarding = 0
# Syn flood protection
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_syn_retries = 2
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_max_syn_backlog = 4096
# Ignore ICMP redirects
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0
# Ignore send redirects
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
# Disable source packet routing
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
net.ipv6.conf.default.accept_source_route = 0
# Reverse path filtering
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
# Log martian packets
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1
# Ignore ICMP ping requests
net.ipv4.icmp_echo_ignore_all = 0
net.ipv4.icmp_echo_ignore_broadcasts = 1
# Ignore bogus ICMP errors
net.ipv4.icmp_ignore_bogus_error_responses = 1
# Enable TCP/IP stack hardening
kernel.randomize_va_space = 2
kernel.exec-shield = 1
kernel.kptr_restrict = 2
kernel.dmesg_restrict = 1
# Restrict kernel pointers in /proc
kernel.kptr_restrict = 2
Apply changes:
sudo sysctl -p
sudo sysctl --system
User Account Security
Disable Root Login
Never allow direct root login via SSH:
Edit /etc/ssh/sshd_config:
PermitRootLogin no
Strong Password Policies
Configure password complexity requirements:
Edit /etc/security/pwquality.conf:
# Password minimum length
minlen = 14
# Require complexity
dcredit = -1 # At least one digit
ucredit = -1 # At least one uppercase
lcredit = -1 # At least one lowercase
ocredit = -1 # At least one special character
# Reject passwords with username
usercheck = 1
# Maximum consecutive characters
maxrepeat = 3
Password Aging
Enforce password expiration policies:
Edit /etc/login.defs:
PASS_MAX_DAYS 90
PASS_MIN_DAYS 1
PASS_WARN_AGE 7
Apply to existing users:
sudo chage -M 90 -m 1 -W 7 username
Account Lockout
Prevent brute force attacks with account lockouts:
Edit /etc/security/faillock.conf:
# Lock account after 5 failed attempts
deny = 5
# Unlock time (seconds)
unlock_time = 900
# Root account also subject to lockout
even_deny_root
SSH Hardening
Key-Based Authentication
Disable password authentication entirely:
# Generate SSH key on client
ssh-keygen -t ed25519 -a 100
# Copy to server
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server
Configure SSH daemon (/etc/ssh/sshd_config):
# Authentication
PubkeyAuthentication yes
PasswordAuthentication no
PermitEmptyPasswords no
ChallengeResponseAuthentication no
UsePAM yes
# Root login
PermitRootLogin no
# Protocol
Protocol 2
# Key types
HostKey /etc/ssh/ssh_host_ed25519_key
HostKey /etc/ssh/ssh_host_rsa_key
# Ciphers and algorithms
KexAlgorithms curve25519-sha256,[email protected]
Ciphers [email protected],[email protected],[email protected],aes256-ctr,aes192-ctr,aes128-ctr
MACs [email protected],[email protected],hmac-sha2-512,hmac-sha2-256
# Connection settings
ClientAliveInterval 300
ClientAliveCountMax 2
MaxAuthTries 3
MaxSessions 2
LoginGraceTime 60
# Limit users
AllowUsers deployuser adminuser
Change Default SSH Port
Reduce automated attacks by changing the default port:
# Edit SSH config
Port 2222
# Update firewall
sudo ufw allow 2222/tcp
sudo ufw delete allow 22/tcp
# Restart SSH
sudo systemctl restart sshd
Firewall Configuration
UFW (Ubuntu/Debian)
Implement a strict firewall policy:
# Install UFW
sudo apt-get install ufw
# Default policies
sudo ufw default deny incoming
sudo ufw default allow outgoing
# Allow SSH (custom port)
sudo ufw allow 2222/tcp
# Allow HTTP/HTTPS
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# Rate limit SSH
sudo ufw limit 2222/tcp
# Enable firewall
sudo ufw enable
# Check status
sudo ufw status verbose
Firewalld (CentOS/Rocky)
# Install firewalld
sudo dnf install firewalld
sudo systemctl enable --now firewalld
# Set default zone
sudo firewall-cmd --set-default-zone=public
# Configure services
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
# Custom SSH port
sudo firewall-cmd --permanent --add-port=2222/tcp
sudo firewall-cmd --permanent --remove-service=ssh
# Rich rules for rate limiting
sudo firewall-cmd --permanent --add-rich-rule='rule service name=ssh limit value=10/m accept'
# Reload
sudo firewall-cmd --reload
Mandatory Access Control
SELinux Configuration
For Red Hat-based systems:
# Check SELinux status
sestatus
# Set enforcing mode
sudo setenforce 1
# Make permanent
sudo sed -i 's/SELINUX=.*/SELINUX=enforcing/' /etc/selinux/config
Manage SELinux contexts:
# Relabel filesystem
sudo touch /.autorelabel
sudo reboot
# Check file contexts
ls -Z /path/to/file
# Restore default context
sudo restorecon -Rv /path/to/directory
AppArmor Configuration
For Debian-based systems:
# Install AppArmor
sudo apt-get install apparmor apparmor-utils
# Check status
sudo aa-status
# Enable profiles
sudo aa-enforce /etc/apparmor.d/*
# Create custom profile
sudo aa-genprof /usr/bin/application
File System Security
Partition Security with Mount Options
Edit /etc/fstab with secure mount options:
/dev/sda1 / ext4 defaults,nodev,nosuid,noexec 1 1
/dev/sda2 /home ext4 defaults,nodev,nosuid 1 2
/dev/sda3 /tmp ext4 defaults,nodev,nosuid,noexec 1 2
/dev/sda4 /var ext4 defaults,nodev 1 2
/dev/sda5 /var/tmp ext4 defaults,nodev,nosuid,noexec 1 2
tmpfs /dev/shm tmpfs defaults,nodev,nosuid,noexec 0 0
Apply immediately:
sudo mount -o remount /tmp
sudo mount -o remount /var/tmp
File Permission Hardening
Set restrictive default permissions:
# Set umask in /etc/profile and /etc/bash.bashrc
umask 027
# Secure sensitive files
sudo chmod 600 /etc/ssh/sshd_config
sudo chmod 600 /boot/grub/grub.cfg
sudo chmod 644 /etc/passwd
sudo chmod 640 /etc/shadow
sudo chmod 640 /etc/gshadow
Find and fix world-writable files:
# Find world-writable files
sudo find / -xdev -type f -perm -0002 -ls
# Find files without owner
sudo find / -xdev -nouser -o -nogroup
# Find SUID/SGID files
sudo find / -xdev -type f \( -perm -4000 -o -perm -2000 \) -ls
Process and Service Hardening
Disable Unnecessary Services
# List enabled services
systemctl list-unit-files --type=service --state=enabled
# Disable unnecessary services
sudo systemctl disable cups
sudo systemctl disable avahi-daemon
sudo systemctl disable bluetooth
Restrict Core Dumps
Prevent sensitive data leakage through core dumps:
Edit /etc/security/limits.conf:
* hard core 0
Create /etc/sysctl.d/50-coredump.conf:
kernel.core_pattern = |/bin/false
fs.suid_dumpable = 0
Monitoring and Logging
Centralized Logging
Configure rsyslog for remote logging:
Edit /etc/rsyslog.conf:
# Send logs to remote server
*.* @@logserver.example.com:514
Audit Logging with Auditd
# Install auditd
sudo apt-get install auditd audispd-plugins
# Enable and start
sudo systemctl enable auditd
sudo systemctl start auditd
Configure audit rules in /etc/audit/rules.d/hardening.rules:
# Delete all existing rules
-D
# Buffer size
-b 8192
# Failure mode
-f 1
# Monitor authentication
-w /etc/passwd -p wa -k passwd_changes
-w /etc/group -p wa -k group_changes
-w /etc/shadow -p wa -k shadow_changes
-w /etc/sudoers -p wa -k sudoers_changes
# Monitor login/logout
-w /var/log/lastlog -p wa -k logins
-w /var/run/faillock/ -p wa -k logins
# Monitor network changes
-w /etc/hosts -p wa -k network_changes
-w /etc/network/ -p wa -k network_changes
# Monitor privilege escalation
-w /usr/bin/sudo -p x -k privilege_escalation
-w /usr/bin/su -p x -k privilege_escalation
# Monitor SSH
-w /etc/ssh/sshd_config -p wa -k sshd_config
# System calls
-a always,exit -F arch=b64 -S execve -k exec
-a always,exit -F arch=b64 -S connect -k network_connect
Reload rules:
sudo augenrules --load
sudo systemctl restart auditd
Log Retention
Configure log rotation in /etc/logrotate.d/rsyslog:
/var/log/syslog
/var/log/auth.log
{
rotate 90
daily
missingok
notifempty
compress
delaycompress
postrotate
/usr/lib/rsyslog/rsyslog-rotate
endscript
}
Intrusion Detection and Prevention
Fail2Ban Configuration
# Install Fail2Ban
sudo apt-get install fail2ban
# Create local configuration
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
Edit /etc/fail2ban/jail.local:
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 5
destemail = [email protected]
sendername = Fail2Ban
action = %(action_mwl)s
[sshd]
enabled = true
port = 2222
logpath = /var/log/auth.log
maxretry = 3
bantime = 86400
AIDE (Advanced Intrusion Detection Environment)
# Install AIDE
sudo apt-get install aide
# Initialize database
sudo aideinit
# Move database
sudo mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db
# Run checks
sudo aide --check
# Automate with cron
echo "0 3 * * * root /usr/bin/aide --check | mail -s 'AIDE Report' [email protected]" | sudo tee -a /etc/crontab
Incident Response Procedures
Detection and Analysis
When suspicious activity is detected:
# Check active connections
sudo ss -tupn
sudo netstat -tupn
# Review authentication logs
sudo tail -100 /var/log/auth.log
sudo journalctl -u sshd -n 100
# Check for new users
sudo tail /etc/passwd
sudo tail /etc/shadow
# Identify suspicious processes
ps aux | grep -v root
ps aux --sort=-pcpu | head -10
Containment
# Block attacking IP
sudo ufw deny from <attacking-ip>
sudo iptables -I INPUT -s <attacking-ip> -j DROP
# Disable compromised account
sudo usermod -L compromised-user
sudo passwd -l compromised-user
# Kill suspicious processes
sudo kill -9 <pid>
# Disconnect network (if necessary)
sudo ip link set eth0 down
Evidence Collection
# Capture system state
sudo ps aux > /root/incident-$(date +%Y%m%d-%H%M%S)-ps.txt
sudo netstat -tupn > /root/incident-$(date +%Y%m%d-%H%M%S)-netstat.txt
sudo ss -tupn > /root/incident-$(date +%Y%m%d-%H%M%S)-ss.txt
# Copy logs
sudo tar czf /root/incident-$(date +%Y%m%d-%H%M%S)-logs.tar.gz /var/log/
# Memory dump (if installed)
sudo dd if=/dev/mem of=/root/memory-dump-$(date +%Y%m%d-%H%M%S).img
Recovery
# Change all passwords
sudo passwd root
sudo passwd username
# Regenerate SSH host keys
sudo rm /etc/ssh/ssh_host_*
sudo dpkg-reconfigure openssh-server
# Update all packages
sudo apt-get update && sudo apt-get upgrade -y
# Review and close unnecessary ports
sudo ss -tuln
Compliance Considerations
PCI-DSS Requirements
For payment card processing:
- Strong access control (Requirement 7, 8)
- Encrypt data transmission (Requirement 4)
- Maintain audit logs (Requirement 10)
- Regular security testing (Requirement 11)
- Vulnerability management (Requirement 6)
HIPAA Compliance
For healthcare data:
- Implement access controls
- Audit controls and logging
- Encryption of ePHI
- Regular risk assessments
GDPR Requirements
For EU personal data:
- Data protection by design
- Pseudonymization and encryption
- Ability to restore data availability
- Regular testing of security measures
Implementation Checklist
# Verify compliance controls
- [ ] Multi-factor authentication enabled
- [ ] Full disk encryption configured
- [ ] Audit logging active and monitored
- [ ] Regular vulnerability scans scheduled
- [ ] Incident response plan documented
- [ ] Data retention policies configured
- [ ] Backup and recovery tested
- [ ] Security awareness training completed
Continuous Security Maintenance
Regular Security Audits
Schedule monthly security reviews:
#!/bin/bash
# Security audit script
echo "=== Security Audit $(date) ===" > /root/security-audit.log
# Check for updates
apt-get -s upgrade >> /root/security-audit.log
# List listening ports
echo -e "\n=== Listening Ports ===" >> /root/security-audit.log
ss -tuln >> /root/security-audit.log
# Check failed login attempts
echo -e "\n=== Failed Login Attempts ===" >> /root/security-audit.log
grep "Failed password" /var/log/auth.log | tail -20 >> /root/security-audit.log
# World-writable files
echo -e "\n=== World-Writable Files ===" >> /root/security-audit.log
find / -xdev -type f -perm -0002 >> /root/security-audit.log 2>/dev/null
# SUID files
echo -e "\n=== SUID/SGID Files ===" >> /root/security-audit.log
find / -xdev -type f \( -perm -4000 -o -perm -2000 \) >> /root/security-audit.log 2>/dev/null
Vulnerability Scanning
# Schedule weekly vulnerability scans
0 2 * * 0 /usr/bin/lynis audit system --cronjob > /var/log/lynis/$(date +\%Y\%m\%d).log
Security Update Management
Establish a patch management schedule:
- Critical security patches: Within 24 hours
- Important security patches: Within 7 days
- Normal updates: Monthly maintenance window
- Test updates in staging before production
Conclusion
Linux server hardening is a comprehensive, ongoing process that requires systematic implementation of security controls across multiple layers. By following this guide, you've established a robust security foundation that addresses:
Prevention: Through strong authentication, firewall rules, and access controls Detection: Via comprehensive logging, monitoring, and intrusion detection systems Response: With documented incident response procedures and evidence collection methods
Remember that security is not a destination but a continuous journey. The threat landscape evolves constantly, requiring regular reassessment of your security posture. Maintain vigilance through:
- Weekly review of security logs
- Monthly vulnerability scans
- Quarterly security audits
- Annual penetration testing
- Continuous education on emerging threats
A properly hardened Linux server significantly reduces your attack surface and provides multiple defensive layers. However, hardening must be balanced with operational requirements and usability. Document all changes, maintain backups, and test security configurations regularly.
The investment in comprehensive server hardening pays dividends through reduced security incidents, improved compliance posture, and protection of critical business assets. Start with the fundamentals outlined in this guide, then progressively implement advanced security controls as your security maturity evolves.
Stay informed about new vulnerabilities, follow security mailing lists for your Linux distribution, and participate in the security community to maintain awareness of emerging threats and best practices.


