Introduction
Server security is not a one-time task but an ongoing practice. A single misconfiguration or unpatched vulnerability can lead to complete system compromise. This guide covers essential Linux server hardening practices that form the foundation of a secure infrastructure.
Initial Server Setup
Create Non-Root User
# Create user
adduser deployer
# Add to the sudo group
usermod -aG sudo deployer
# Or on CentOS/RHEL
usermod -aG wheel deployer
# Test sudo access
su - deployer
sudo whoami
Configure SSH
# Generate an SSH key on the local machine
ssh-keygen -t ed25519 -C "[email protected]"
# Copy the public key to the server
ssh-copy-id -i ~/.ssh/id_ed25519.pub deployer@server
Edit /etc/ssh/sshd_config:
# Disable root login
PermitRootLogin no
# Disable password authentication
PasswordAuthentication no
# Use SSH key only
PubkeyAuthentication yes
# Disable empty passwords
PermitEmptyPasswords no
# Limit users who can SSH
AllowUsers deployer
# Change the default port (optional)
Port 2222
# Timeout settings
ClientAliveInterval 300
ClientAliveCountMax 2
# Disable X11 forwarding
X11Forwarding no
Restart SSH:
sudo systemctl restart sshd
Firewall Configuration
UFW (Ubuntu/Debian)
# Install
sudo apt install ufw
# Default policies
sudo ufw default deny incoming
sudo ufw default allow outgoing
# Allow SSH (before enabling!)
sudo ufw allow 22/tcp
# Or a custom port
sudo ufw allow 2222/tcp
# Allow web traffic
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# Enable firewall
sudo ufw enable
# Check status
sudo ufw status verbose
firewalld (CentOS/RHEL)
# Start and enable
sudo systemctl start firewalld
sudo systemctl enable firewalld
# Add services
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
# Trust internal network
sudo firewall-cmd --zone=trusted --add-source=10.0.0.0/8 --permanent
# Reload
sudo firewall-cmd --reload
# Check status
sudo firewall-cmd --list-all
Keep System Updated
Automatic Security Updates
Ubuntu/Debian
# Install unattended-upgrades
sudo apt install unattended-upgrades
# Configure
sudo dpkg-reconfigure -plow unattended-upgrades
Edit /etc/apt/apt.conf.d/50unattended-upgrades:
Unattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}-security";
};
Unattended-Upgrade::AutoFixInterruptedDpkg "true";
Unattended-Upgrade::Remove-Unused-Dependencies "true";
Unattended-Upgrade::Automatic-Reboot "false";
CentOS/RHEL
# Install
sudo dnf install dnf-automatic
# Configure for security updates only
sudo vi /etc/dnf/automatic.conf
# Set: upgrade_type = security
# Enable timer
sudo systemctl enable --now dnf-automatic.timer
Fail2ban - Brute Force Protection
# Install
sudo apt install fail2ban # Debian/Ubuntu
sudo dnf install fail2ban # CentOS/RHEL
# Configure
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
Edit /etc/fail2ban/jail.local:
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 5
banaction = iptables-multiport
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
# Start
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
# Check status
sudo fail2ban-client status sshd
User and Permission Security
Password Policies
Edit /etc/login.defs:
PASS_MAX_DAYS 90
PASS_MIN_DAYS 7
PASS_WARN_AGE 14
PASS_MIN_LEN 12
Secure Sensitive Files
# Restrict shadow file
sudo chmod 640 /etc/shadow
# Secure cron
sudo chmod 700 /etc/crontab
# Restrict SSH directory
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
Monitor Privileged Access
# Log sudo commands
echo 'Defaults logfile="/var/log/sudo.log"' | sudo tee -a /etc/sudoers.d/logging
Service Hardening
Disable Unnecessary Services
# List enabled services
sudo systemctl list-unit-files --type=service --state=enabled
# Disable unneeded services
sudo systemctl disable bluetooth
sudo systemctl disable cups
sudo systemctl disable avahi-daemon
Remove Unused Packages
# Debian/Ubuntu
sudo apt autoremove
# CentOS/RHEL
sudo dnf autoremove
Intrusion Detection
AIDE (Advanced Intrusion Detection Environment)
# Install
sudo apt install aide # Debian/Ubuntu
# Initialize database
sudo aideinit
# Check for changes
sudo aide --check
Monitor Logs
# Install logwatch
sudo apt install logwatch
# Configure daily emails
sudo vi /etc/cron.daily/00logwatch
# Add: /usr/sbin/logwatch --output mail --mailto [email protected] --detail high
Kernel Security
sysctl Hardening
Create /etc/sysctl.d/99-security.conf:
# Disable IP forwarding (unless router/VPN)
net.ipv4.ip_forward = 0
# Ignore ICMP redirects
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
# Disable source routing
net.ipv4.conf.all.accept_source_route = 0
# Enable SYN flood protection
net.ipv4.tcp_syncookies = 1
# Ignore ping broadcasts
net.ipv4.icmp_echo_ignore_broadcasts = 1
# Log martian packets
net.ipv4.conf.all.log_martians = 1
# Disable IPv6 (if not needed)
net.ipv6.conf.all.disable_ipv6 = 1
Apply:
sudo sysctl -p /etc/sysctl.d/99-security.conf
AppArmor/SELinux
AppArmor (Ubuntu)
# Check status
sudo aa-status
# Enforce profiles
sudo aa-enforce /etc/apparmor.d/*
SELinux (CentOS/RHEL)
# Check status
getenforce
# Set to enforcing (edit /etc/selinux/config)
SELINUX=enforcing
# Check for denials
sudo ausearch -m avc -ts today
Audit and Monitoring
auditd
# Install
sudo apt install auditd # Debian/Ubuntu
# Monitor sensitive files
sudo auditctl -w /etc/passwd -p wa -k passwd_changes
sudo auditctl -w /etc/shadow -p wa -k shadow_changes
sudo auditctl -w /etc/sudoers -p wa -k sudoers_changes
# Make rules persistent
# Add to /etc/audit/rules.d/audit.rules
# View audit logs
sudo ausearch -k passwd_changes
Backup Verification
# Create backup script
cat << 'EOF' > /usr/local/bin/backup-verify.sh
#!/bin/bash
BACKUP_DIR=/backup
DATE=$(date +%Y%m%d)
# Create backup
tar -czf $BACKUP_DIR/etc-$DATE.tar.gz /etc
# Verify backup
tar -tzf $BACKUP_DIR/etc-$DATE.tar.gz > /dev/null 2>&1
if [ $? -eq 0 ]; then
echo "Backup verified successfully"
else
echo "Backup verification FAILED" | mail -s "Backup Alert" [email protected]
fi
EOF
chmod +x /usr/local/bin/backup-verify.sh
Security Checklist
Initial Setup
- [ ] Create non-root user with sudo
- [ ] Disable root SSH login
- [ ] Enable SSH key authentication only
- [ ] Configure firewall (deny by default)
- [ ] Install and configure fail2ban
Ongoing
- [ ] Enable automatic security updates
- [ ] Review logs regularly
- [ ] Monitor for unauthorized changes
- [ ] Test backups monthly
- [ ] Audit user accounts quarterly
- [ ] Update and rotate SSH keys annually
Conclusion
Server security requires multiple layers of defense. Start with SSH hardening and firewall configuration, add brute force protection with fail2ban, and implement intrusion detection. Regular updates and monitoring ensure your security posture remains strong over time.