Linux System Hardening: Essential Security Practices for Servers
In today's threat landscape, proper security hardening is no longer optional—it's a necessity. Linux servers power everything from small websites to enterprise infrastructure, making them prime targets for attackers. This guide will walk you through the essential practices for hardening your Linux servers to minimize vulnerabilities while maintaining functionality. Why Server Hardening Matters Server hardening is the process of enhancing security by reducing the attack surface, eliminating unnecessary services, and configuring systems with security as a priority. An unhardened server is like a house with unlocked doors and windows—an invitation to intruders. The benefits of proper hardening include: Reduced risk of successful attacks Protection against common vulnerability exploits Compliance with security standards and regulations Early detection of breach attempts Minimized damage if a breach occurs Let's dive into practical steps you can implement today. 1. Secure User Authentication Implement Strong Password Policies # Edit the PAM configuration sudo nano /etc/security/pwquality.conf # Add/modify these settings minlen = 12 # Minimum password length minclass = 3 # Require characters from at least 3 classes (uppercase, lowercase, digits, others) maxrepeat = 2 # No more than 2 identical consecutive characters difok = 4 # At least 4 characters must be different from the previous password enforce_for_root # Apply these rules to the root account Configure Password Aging # Edit login.defs to set password expiration sudo nano /etc/login.defs # Add/modify these settings PASS_MAX_DAYS 90 # Maximum password age PASS_MIN_DAYS 7 # Minimum days between password changes PASS_WARN_AGE 14 # Warning days before password expires Disable Root Login # Edit SSH configuration sudo nano /etc/ssh/sshd_config # Set the following PermitRootLogin no Implement SSH Key Authentication # On your local machine, generate SSH key pair ssh-keygen -t ed25519 -C "your_email@example.com" # Copy the public key to your server ssh-copy-id username@server_ip # Disable password authentication in sshd_config sudo nano /etc/ssh/sshd_config # Set the following PasswordAuthentication no ChallengeResponseAuthentication no # Restart SSH service sudo systemctl restart sshd 2. Minimize Attack Surface Remove Unnecessary Services and Packages # List installed packages sudo apt list --installed # Debian/Ubuntu sudo dnf list installed # CentOS/RHEL/Fedora # Remove unnecessary packages sudo apt purge package_name # Debian/Ubuntu sudo dnf remove package_name # CentOS/RHEL/Fedora # Common services to evaluate sudo systemctl status apache2 nginx postfix dovecot telnet ftp rsh-server rlogin-server Disable Unused Services # List running services sudo systemctl list-units --type=service --state=running # Disable unnecessary services sudo systemctl stop service_name sudo systemctl disable service_name Close Unnecessary Ports # Check open ports sudo ss -tulpn # Configure firewall (using UFW as an example) sudo apt install ufw sudo ufw default deny incoming sudo ufw default allow outgoing sudo ufw allow 22/tcp sudo ufw allow 80/tcp sudo ufw allow 443/tcp sudo ufw enable 3. Keep Systems Updated Configure Automatic Security Updates For Debian/Ubuntu: # Install unattended upgrades sudo apt install unattended-upgrades apt-listchanges # Configure automatic updates sudo dpkg-reconfigure -plow unattended-upgrades # Edit the configuration sudo nano /etc/apt/apt.conf.d/50unattended-upgrades # Ensure the following lines are uncommented Unattended-Upgrade::Allowed-Origins { "${distro_id}:${distro_codename}-security"; }; For CentOS/RHEL: # Install dnf-automatic sudo dnf install dnf-automatic # Configure automatic updates sudo nano /etc/dnf/automatic.conf # Set to 'yes' to enable apply_updates = yes # Enable and start service sudo systemctl enable --now dnf-automatic.timer Check for Updates Regularly # For Debian/Ubuntu sudo apt update && sudo apt list --upgradable # For CentOS/RHEL/Fedora sudo dnf check-update 4. Implement File System Security Configure Proper File Permissions # Find world-writable files sudo find / -xdev -type f -perm -0002 -ls # Find files with no owner sudo find / -xdev -nouser -o -nogroup -ls # Set appropriate permissions sudo chmod 600 sensitive_file sudo chown user:group file_or_directory Set Up Disk Encryption For new installations, use LUKS encryption during the setup process. For existing servers: # Install cryptsetup sudo apt install cryptsetup # Debian/Ubuntu sudo dnf install cryptsetup # CentOS/RHEL/Fedora # Create an encrypted container (for individual directories/files) sudo

In today's threat landscape, proper security hardening is no longer optional—it's a necessity. Linux servers power everything from small websites to enterprise infrastructure, making them prime targets for attackers. This guide will walk you through the essential practices for hardening your Linux servers to minimize vulnerabilities while maintaining functionality.
Why Server Hardening Matters
Server hardening is the process of enhancing security by reducing the attack surface, eliminating unnecessary services, and configuring systems with security as a priority. An unhardened server is like a house with unlocked doors and windows—an invitation to intruders.
The benefits of proper hardening include:
- Reduced risk of successful attacks
- Protection against common vulnerability exploits
- Compliance with security standards and regulations
- Early detection of breach attempts
- Minimized damage if a breach occurs
Let's dive into practical steps you can implement today.
1. Secure User Authentication
Implement Strong Password Policies
# Edit the PAM configuration
sudo nano /etc/security/pwquality.conf
# Add/modify these settings
minlen = 12 # Minimum password length
minclass = 3 # Require characters from at least 3 classes (uppercase, lowercase, digits, others)
maxrepeat = 2 # No more than 2 identical consecutive characters
difok = 4 # At least 4 characters must be different from the previous password
enforce_for_root # Apply these rules to the root account
Configure Password Aging
# Edit login.defs to set password expiration
sudo nano /etc/login.defs
# Add/modify these settings
PASS_MAX_DAYS 90 # Maximum password age
PASS_MIN_DAYS 7 # Minimum days between password changes
PASS_WARN_AGE 14 # Warning days before password expires
Disable Root Login
# Edit SSH configuration
sudo nano /etc/ssh/sshd_config
# Set the following
PermitRootLogin no
Implement SSH Key Authentication
# On your local machine, generate SSH key pair
ssh-keygen -t ed25519 -C "your_email@example.com"
# Copy the public key to your server
ssh-copy-id username@server_ip
# Disable password authentication in sshd_config
sudo nano /etc/ssh/sshd_config
# Set the following
PasswordAuthentication no
ChallengeResponseAuthentication no
# Restart SSH service
sudo systemctl restart sshd
2. Minimize Attack Surface
Remove Unnecessary Services and Packages
# List installed packages
sudo apt list --installed # Debian/Ubuntu
sudo dnf list installed # CentOS/RHEL/Fedora
# Remove unnecessary packages
sudo apt purge package_name # Debian/Ubuntu
sudo dnf remove package_name # CentOS/RHEL/Fedora
# Common services to evaluate
sudo systemctl status apache2 nginx postfix dovecot telnet ftp rsh-server rlogin-server
Disable Unused Services
# List running services
sudo systemctl list-units --type=service --state=running
# Disable unnecessary services
sudo systemctl stop service_name
sudo systemctl disable service_name
Close Unnecessary Ports
# Check open ports
sudo ss -tulpn
# Configure firewall (using UFW as an example)
sudo apt install ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
3. Keep Systems Updated
Configure Automatic Security Updates
For Debian/Ubuntu:
# Install unattended upgrades
sudo apt install unattended-upgrades apt-listchanges
# Configure automatic updates
sudo dpkg-reconfigure -plow unattended-upgrades
# Edit the configuration
sudo nano /etc/apt/apt.conf.d/50unattended-upgrades
# Ensure the following lines are uncommented
Unattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}-security";
};
For CentOS/RHEL:
# Install dnf-automatic
sudo dnf install dnf-automatic
# Configure automatic updates
sudo nano /etc/dnf/automatic.conf
# Set to 'yes' to enable
apply_updates = yes
# Enable and start service
sudo systemctl enable --now dnf-automatic.timer
Check for Updates Regularly
# For Debian/Ubuntu
sudo apt update && sudo apt list --upgradable
# For CentOS/RHEL/Fedora
sudo dnf check-update
4. Implement File System Security
Configure Proper File Permissions
# Find world-writable files
sudo find / -xdev -type f -perm -0002 -ls
# Find files with no owner
sudo find / -xdev -nouser -o -nogroup -ls
# Set appropriate permissions
sudo chmod 600 sensitive_file
sudo chown user:group file_or_directory
Set Up Disk Encryption
For new installations, use LUKS encryption during the setup process. For existing servers:
# Install cryptsetup
sudo apt install cryptsetup # Debian/Ubuntu
sudo dnf install cryptsetup # CentOS/RHEL/Fedora
# Create an encrypted container (for individual directories/files)
sudo cryptsetup luksFormat /dev/sdX
sudo cryptsetup luksOpen /dev/sdX secure_data
sudo mkfs.ext4 /dev/mapper/secure_data
sudo mount /dev/mapper/secure_data /mnt/secure
Configure Secure Mount Options
# Edit fstab to add security options
sudo nano /etc/fstab
# Add options like:
/dev/sda1 /mount_point ext4 defaults,noexec,nosuid,nodev 0 0
5. Network Security Hardening
Configure Firewall Rules
Using UFW (Ubuntu):
sudo ufw limit ssh # Rate-limit SSH connections
sudo ufw deny from # Block specific IPs
sudo ufw logging on # Enable logging
Using firewalld (CentOS/RHEL):
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
Secure SSH Configuration
sudo nano /etc/ssh/sshd_config
# Add/modify these settings
Protocol 2 # Use SSH protocol 2
Port 2222 # Change default port (optional)
AddressFamily inet # Use IPv4 only (if IPv6 not needed)
PermitRootLogin no # Prevent direct root login
MaxAuthTries 3 # Limit authentication attempts
MaxSessions 2 # Limit sessions per connection
PubkeyAuthentication yes # Allow public key authentication
PasswordAuthentication no # Disable password authentication
PermitEmptyPasswords no # Never allow empty passwords
ClientAliveInterval 300 # Close idle sessions after 5 minutes
ClientAliveCountMax 0 # Don't send keepalive messages
LoginGraceTime 30 # Reduce login grace time
X11Forwarding no # Disable X11 forwarding if not needed
AllowUsers user1 user2 # Specify allowed users
# Restart SSH service
sudo systemctl restart sshd
Enable Fail2Ban to Prevent Brute Force Attacks
# Install Fail2Ban
sudo apt install fail2ban # Debian/Ubuntu
sudo dnf install fail2ban # CentOS/RHEL/Fedora
# Create local configuration
sudo nano /etc/fail2ban/jail.local
# Add configuration
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
# Enable and start service
sudo systemctl enable --now fail2ban
6. Implement Kernel Hardening
Configure Secure sysctl Parameters
sudo nano /etc/sysctl.conf
# Add/modify these security settings
# Prevent IP spoofing
net.ipv4.conf.all.rp_filter=1
net.ipv4.conf.default.rp_filter=1
# Disable IP source routing
net.ipv4.conf.all.accept_source_route=0
net.ipv4.conf.default.accept_source_route=0
# Disable ICMP redirect acceptance
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
# Enable IP spoofing protection
net.ipv4.conf.all.rp_filter=1
net.ipv4.conf.default.rp_filter=1
# Protect against TCP time-wait assassinations
net.ipv4.tcp_rfc1337=1
# Disable packet forwarding
net.ipv4.ip_forward=0
net.ipv6.conf.all.forwarding=0
# Apply changes
sudo sysctl -p
Enable and Configure AppArmor/SELinux
For Ubuntu (AppArmor):
# Check AppArmor status
sudo apparmor_status
# Enable AppArmor
sudo systemctl enable --now apparmor
For CentOS/RHEL (SELinux):
# Check SELinux status
sestatus
# Enable SELinux in enforcing mode
sudo nano /etc/selinux/config
# Set SELINUX=enforcing
7. Implement Logging and Monitoring
Configure Centralized Logging
# Install rsyslog if not already installed
sudo apt install rsyslog # Debian/Ubuntu
sudo dnf install rsyslog # CentOS/RHEL/Fedora
# Configure for centralized logging
sudo nano /etc/rsyslog.conf
# Add configuration for remote logging
*.* @logserver:514 # UDP
*.* @@logserver:514 # TCP
# Restart service
sudo systemctl restart rsyslog
Set Up Logwatch for Regular System Reports
# Install logwatch
sudo apt install logwatch # Debian/Ubuntu
sudo dnf install logwatch # CentOS/RHEL/Fedora
# Configure daily reports
sudo nano /etc/logwatch/conf/logwatch.conf
# Set options
Output = mail
Format = html
MailTo = admin@example.com
Detail = High
Configure Auditd for System Auditing
# Install auditd
sudo apt install auditd audispd-plugins # Debian/Ubuntu
sudo dnf install audit audispd-plugins # CentOS/RHEL/Fedora
# Configure basic audit rules
sudo nano /etc/audit/rules.d/audit.rules
# Add security-focused rules
-w /etc/passwd -p wa -k identity
-w /etc/group -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/sudoers -p wa -k identity
-a always,exit -F arch=b64 -S execve -k exec
# Restart service
sudo systemctl restart auditd
8. Regular Security Audits
Install and Run Lynis
# Install Lynis
sudo apt install lynis # Debian/Ubuntu
sudo dnf install lynis # CentOS/RHEL/Fedora
# Or download directly from website
cd /tmp
wget https://downloads.cisofy.com/lynis/lynis-3.0.8.tar.gz
tar xvzf lynis-3.0.8.tar.gz
cd lynis
sudo ./lynis audit system
Run Security Scanning With OpenVAS
# For Ubuntu
sudo apt install openvas
sudo gvm-setup
sudo gvm-start
Set Up Regular Security Audits
Use cron jobs to regularly run security checks:
sudo crontab -e
# Add a weekly Lynis audit
0 2 * * 0 /usr/bin/lynis audit system --cronjob > /var/log/lynis-weekly.log
9. Backup and Recovery
Implement Regular Backups
# Install backup tool (e.g., restic)
sudo apt install restic # Debian/Ubuntu
sudo dnf install restic # CentOS/RHEL/Fedora
# Initialize repository
restic init --repo /path/to/backup/repository
# Set up regular backups
restic backup --repo /path/to/backup/repository /path/to/data
# Set up cron job for regular backups
sudo crontab -e
# Add daily backup
0 3 * * * /usr/bin/restic backup --repo /path/to/backup/repository /path/to/data >> /var/log/backup.log 2>&1
Test Backup Restoration
Regularly test your backup restoration process to ensure it works when needed:
# Test restoration to a temporary location
restic restore latest --target /tmp/restore-test --repo /path/to/backup/repository
10. Establish a Security Update Process
Create a documented process for:
- Monitoring security advisories for your OS and installed packages
- Testing updates in a non-production environment
- Applying updates during maintenance windows
- Verifying system functionality after updates
- Rolling back if issues occur
Conclusion
Server hardening is an ongoing process, not a one-time task. Implement these practices as a baseline, then continue to improve your security posture over time. Regular audits, updates, and monitoring are crucial to maintaining a secure server environment.
Remember that security is about defense in depth—no single measure provides complete protection. By implementing multiple layers of security controls, you make your systems significantly more resistant to attacks.
What security practices have you found most effective for your Linux servers? Share your experiences in the comments!
This article provides general guidance. Always adapt security measures to your specific environment and requirements. For critical systems, consider consulting with a security professional.