Back to articles
Security7 min read

Hardening Linux Servers for Production

Essential security configurations including SSH hardening, firewall rules, fail2ban, and CIS benchmark compliance.

2024-07-05

Hardening Linux Servers for Production

Every server exposed to the internet is a target. Whether you're running a single VM or managing a fleet of hundreds, security hardening is not optional — it's the baseline. Here are the essential configurations I apply to every production Linux server.

SSH Hardening

SSH is the front door to your server. Lock it down:

# /etc/ssh/sshd_config

# Disable root login
PermitRootLogin no

# Disable password authentication
PasswordAuthentication no
PubkeyAuthentication yes

# Restrict to specific users
AllowUsers deploy admin

# Use strong key exchange algorithms
KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256

# Limit authentication attempts
MaxAuthTries 3
LoginGraceTime 30

# Disable unused features
X11Forwarding no
AllowTcpForwarding no
AllowAgentForwarding no

# Change default port (security through obscurity, but reduces noise)
Port 2222

After modifying sshd_config, always test with a new session before closing your current one. Getting locked out of a remote server is not fun.

Firewall with UFW

I use UFW (Uncomplicated Firewall) for its simplicity, backed by iptables:

# Reset and set defaults
ufw --force reset
ufw default deny incoming
ufw default allow outgoing

# Allow SSH on custom port
ufw allow 2222/tcp comment 'SSH'

# Allow web traffic
ufw allow 80/tcp comment 'HTTP'
ufw allow 443/tcp comment 'HTTPS'

# Rate limit SSH
ufw limit 2222/tcp

# Enable
ufw --force enable

The limit rule automatically blocks IPs that attempt more than 6 connections within 30 seconds — a simple but effective brute-force protection.

Fail2ban

Fail2ban monitors log files and bans IPs that show malicious patterns:

# /etc/fail2ban/jail.local

[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 3
banaction = ufw

[sshd]
enabled = true
port = 2222
logpath = /var/log/auth.log
maxretry = 3

[nginx-http-auth]
enabled = true
logpath = /var/log/nginx/error.log

[nginx-limit-req]
enabled = true
logpath = /var/log/nginx/error.log

With this configuration, three failed SSH attempts within 10 minutes results in a 1-hour ban. For persistent attackers, I configure escalating ban times using fail2ban's recidive jail.

Automatic Security Updates

Enable unattended upgrades for security patches:

apt install unattended-upgradesdpkg-reconfigure -plow unattended-upgrades

Configure /etc/apt/apt.conf.d/50unattended-upgrades:

Unattended-Upgrade::Allowed-Origins {
    "${distro_id}:${distro_codename}-security";
};
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
Unattended-Upgrade::Remove-Unused-Dependencies "true";
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "03:00";

CIS Benchmark Compliance

The CIS (Center for Internet Security) benchmarks provide comprehensive hardening guidelines. Key checks include:

# Ensure permissions on /etc/passwd
chmod 644 /etc/passwd
chmod 600 /etc/shadow

# Disable unused filesystems
echo "install cramfs /bin/true" >> /etc/modprobe.d/disable-filesystems.conf
echo "install freevxfs /bin/true" >> /etc/modprobe.d/disable-filesystems.conf

# Set sticky bit on world-writable directories
df --local -P | awk '{if (NR!=1) print $6}' | \
  xargs -I '{}' find '{}' -xdev -type d -perm -0002 2>/dev/null | \
  xargs -I '{}' chmod a+t '{}'

# Audit system events
apt install auditd
systemctl enable auditd

For automated compliance checking, I use tools like lynis which audits the system against CIS benchmarks and provides a hardening score with actionable recommendations.

Monitoring and Alerting

Hardening without monitoring is incomplete. At minimum, set up:

  • Log aggregation: Ship logs to a central location (Azure Monitor, ELK, Grafana Loki)
  • File integrity monitoring: Use AIDE or OSSEC to detect unauthorized file changes
  • Login notifications: Get alerted on SSH logins from unexpected IPs

Security is a continuous process, not a one-time setup. Review configurations regularly, keep systems updated, and always assume something is trying to get in.

Share this article

Need help with your infrastructure?

Let's discuss your project and find the best solution together.

Get in touch