A comprehensive guide to understanding and implementing Linux server hardening.
4. SSH Security
6. Intrusion Detection & Prevention
Security is not a one-time task — it's an ongoing process. Every server is a potential target, regardless of size or perceived importance. Attackers use automated tools that scan the entire internet for vulnerable systems.
Key principles:
Our scripts implement multiple security layers:
┌──────────────────────────────────────────────┐
│ Layer 7: Application Security │
│ (Your application code, WAF) │
├──────────────────────────────────────────────┤
│ Layer 6: Authentication & Authorization │
│ (SSH keys, sudo, PAM, fail2ban) │
├──────────────────────────────────────────────┤
│ Layer 5: Network Security │
│ (Firewall, rate limiting, IP filtering) │
├──────────────────────────────────────────────┤
│ Layer 4: OS Hardening │
│ (Kernel params, sysctl, module blacklist) │
├──────────────────────────────────────────────┤
│ Layer 3: Filesystem Security │
│ (Permissions, mount options, SUID cleanup) │
├──────────────────────────────────────────────┤
│ Layer 2: Monitoring & Auditing │
│ (auditd, logging, alerting) │
├──────────────────────────────────────────────┤
│ Layer 1: Patch Management │
│ (Automatic security updates) │
└──────────────────────────────────────────────┘
Before hardening, reduce what attackers can target:
# List installed packages
dpkg -l # Debian/Ubuntu
rpm -qa # RHEL/CentOS
# Remove examples
apt purge telnet ftp rsh-client # Debian/Ubuntu
yum remove telnet ftp rsh # RHEL/CentOS# List all enabled services
systemctl list-unit-files --state=enabled
# Disable services you don't need
systemctl disable --now avahi-daemon
systemctl disable --now cups# Check open ports
ss -tulnp # Shows all listening ports
nmap -sT localhost # Port scan yourselfSSH is the primary remote access method and the #1 attack target on internet-facing servers.
Passwords are susceptible to brute-force attacks. An internet-facing SSH server sees thousands of brute-force attempts daily. SSH keys are cryptographically stronger and cannot be brute-forced.
| Setting | Value | Why |
|---|---|---|
PermitRootLogin no | Disables direct root SSH | Forces use of named accounts + sudo for audit trail |
PasswordAuthentication no | Keys only | Eliminates brute-force attacks entirely |
MaxAuthTries 3 | 3 attempts | Limits credential guessing per connection |
ClientAliveInterval 300 | 5 min | Terminates idle sessions to reduce hijacking risk |
AllowAgentForwarding no | Disabled | Prevents agent hijacking on compromised servers |
X11Forwarding no | Disabled | Removes attack vector through X11 protocol |
1. Generate an SSH key pair on your workstation:
ssh-keygen -t ed25519 -C "your-email@example.com"2. Copy the public key to the server:
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server3. Test key-based login in a new terminal before applying hardening
4. Only then run harden-ssh.sh
A firewall should implement the principle of default deny — block everything, then explicitly allow only what's needed.
Incoming: DENY ALL (then allow specific ports)
Outgoing: ALLOW ALL (restrict if possible)
Forward: DENY ALL (unless acting as router)
| Port | Protocol | Service | Who needs access |
|---|---|---|---|
| 22 | TCP | SSH | Admin IPs only |
| 80 | TCP | HTTP | World (if web server) |
| 443 | TCP | HTTPS | World (if web server) |
SSH rate limiting (via ufw limit) allows 6 connections per 30 seconds per IP. This stops brute-force while allowing normal use.
1. Fail2Ban monitors log files for authentication failures
2. After maxretry failures within findtime, the IP is banned
3. Ban lasts for bantime, then the IP is released
4. Recidive jail catches repeat offenders with escalating bans
First offense: 1 hour ban (sshd jail)
DDoS detection: 48 hour ban (sshd-ddos jail)
Repeat offender: 1 week ban (recidive jail)
# Overall status
fail2ban-client status
# SSH jail details
fail2ban-client status sshd
# Currently banned IPs
fail2ban-client get sshd banip
# Unban a specific IP
fail2ban-client set sshd unbanip 192.168.1.100Kernel parameters control fundamental OS behavior. Our sysctl-hardened.conf addresses:
tcp_syncookies=1): Protects against SYN flood DoS attacksrp_filter=1): Drops packets with impossible source addresses (IP spoofing)randomize_va_space=2): Randomizes memory layout, making exploits unreliablesuid_dumpable=0): Prevents SUID programs from creating memory dumps that might contain secrets| Policy | Value | Reasoning |
|---|---|---|
| Min length | 14 chars | NIST 800-63B recommends 8+; 14 provides margin |
| Max age | 365 days | Balance between rotation and user frustration |
| Min age | 7 days | Prevents rapid cycling to reuse old passwords |
| Complexity | Mixed | Uppercase, lowercase, digit, special character |
/var/log/sudo.logroot account → Direct login disabled, use sudo
Admin accounts → sudo access with password
Service accounts → No login shell (/usr/sbin/nologin)
Application user → No sudo, limited file access
Auditing creates a forensic trail. When (not if) a security incident occurs, audit logs tell you:
| Key | What it monitors | Why |
|---|---|---|
time-change | System clock modifications | Attackers change time to hide activity |
identity | User/group file changes | Detect unauthorized account creation |
system-locale | Network config changes | Detect DNS/routing manipulation |
logins | Login/logout events | Track access patterns |
perm_mod | Permission changes | Detect privilege escalation |
access | Failed file access | Detect reconnaissance |
scope | Sudoers changes | Detect privilege granting |
modules | Kernel module operations | Detect rootkit installation |
# Search by key
ausearch -k identity # User/group changes
ausearch -k privilege_escalation # Sudo usage
# Reports
aureport --summary # Overall summary
aureport --auth # Authentication report
aureport --login --summary # Login summary
aureport --failed # Failed operations
# Recent events
ausearch -ts recent # Last 10 minutes
ausearch -ts today # Today's eventsThe #1 cause of successful attacks is unpatched vulnerabilities. The average time between vulnerability disclosure and exploitation is decreasing — automated updates close this window.
Only security updates are auto-applied. Feature updates and major version changes require manual review.
| Risk | Mitigation |
|---|---|
| Update breaks something | Security-only updates are low-risk; test in staging |
| Reboot required | Schedule auto-reboot during maintenance window |
| Package conflicts | Blacklist problematic packages |
| Option | Purpose | Where to apply |
|---|---|---|
nodev | No device files | /tmp, /var/tmp, /dev/shm |
nosuid | No SUID/SGID | /tmp, /var/tmp, /dev/shm |
noexec | No execution | /tmp, /var/tmp, /dev/shm |
SUID (Set User ID) binaries run with the file owner's privileges, not the caller's. A vulnerable SUID-root binary = instant root access for an attacker.
# Find all SUID binaries
find / -xdev -perm -4000 -type f 2>/dev/null
# Common legitimate SUID binaries
/usr/bin/sudo # Needed
/usr/bin/passwd # Needed
/usr/bin/su # Needed (but consider removing)
/usr/bin/chsh # Often unnecessary
/usr/bin/chfn # Often unnecessary
/usr/bin/newgrp # Often unnecessaryReview each SUID binary and remove the bit if not needed:
chmod u-s /usr/bin/chfn # Remove SUID from chfnIf you suspect a compromise:
Powering off destroys volatile evidence (memory, network connections).
# Current connections
ss -tulnp > /tmp/connections.txt
# Running processes
ps auxf > /tmp/processes.txt
# Logged-in users
w > /tmp/users.txt
# Recent logins
last -50 > /tmp/logins.txt
# Recent file modifications
find / -mtime -1 -type f 2>/dev/null > /tmp/modified-files.txt# Failed logins
aureport --auth --failed
# Privilege escalation
ausearch -k privilege_escalation -ts today
# File modifications
ausearch -k perm_mod -ts todayDisconnect from the network if active compromise is confirmed.
Use logs and forensic evidence to determine the attack vector and scope.
Hardening is not one-and-done. Schedule regular reviews:
journalctl -u sshd | grep Failedfail2ban-client status sshdcat /var/log/sudo.logbash filesystem-hardening.sh --audit-onlyawk -F: '$3 >= 1000' /etc/passwd*Guide by Datanest Digital | support@datanest.dev*
Production-ready server hardening automation implementing CIS benchmarks and industry best practices.
Automated Bash scripts and configuration files for securing Ubuntu/Debian and RHEL/CentOS Linux servers. Covers SSH hardening, firewall setup, intrusion detection, kernel tuning, audit logging, and more — all aligned with CIS Benchmark Level 1 and Level 2 recommendations.
Get the full Linux Hardening Scripts and unlock everything.
Get the complete guide with every chapter unlocked, including code samples, diagrams, and best practices.
Access all interactive tools with complete data, all workload profiles, and the full scenario library.
Downloadable source code, configuration files, and working examples from every chapter.
Free updates for life. Every new chapter, tool, and improvement included.