Back to blog
linuxsecurityinfrastructurehardening

Server Hardening Checklist for Production Linux Systems

February 1, 20262 min read

The baseline

Every production server I touch gets the same treatment before anything else runs on it. This isn't theoretical — it's the exact process I follow when spinning up new infrastructure.

Here's the checklist.

1. SSH hardening

The defaults are not good enough. Change them immediately.

# /etc/ssh/sshd_config
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
MaxAuthTries 3
ClientAliveInterval 300
ClientAliveCountMax 2
AllowUsers deploy

Key-only authentication. No root login. Short timeouts. This alone prevents the majority of brute-force attacks.

2. Firewall — deny by default

UFW makes this straightforward:

ufw default deny incoming
ufw default allow outgoing
ufw allow from <management-ip> to any port 22
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable

The critical part: SSH access is only allowed from known management IPs. Everything else is dropped.

3. Fail2Ban

For the attempts that do get through:

# /etc/fail2ban/jail.local
[sshd]
enabled = true
port = ssh
filter = sshd
maxretry = 3
bantime = 3600
findtime = 600

Three failed attempts and you're banned for an hour. Simple and effective.

4. Automated updates

Unattended security updates are non-negotiable:

apt install unattended-upgrades
dpkg-reconfigure -plow unattended-upgrades

Configure it to only apply security patches automatically. Feature updates should still go through your normal deployment pipeline.

5. Container security

If you're running Docker, the defaults need work too:

  • Run containers as non-root users
  • Use read-only filesystems where possible
  • Limit container capabilities with --cap-drop ALL
  • Scan images with trivy before deploying
docker run --read-only --cap-drop ALL --cap-add NET_BIND_SERVICE \
  --user 1000:1000 your-app:latest

6. Monitoring

A hardened server that nobody watches is still a liability. At minimum:

  • System logs — centralized with journald or rsyslog
  • File integrity — monitor /etc, /usr/bin with AIDE or osquery
  • Network traffic — watch for unexpected outbound connections

I use a simple Python script that checks for new listening ports and alerts via webhook if anything unexpected appears.

The principle

Security isn't a product you install. It's a process of reducing attack surface, detecting anomalies, and responding quickly. Every item on this list reduces the window an attacker has to work with.

Start with the basics. Get them right. Then build from there.