Skip to content
Back to Blog
Security11 min read

Server Security Checklist: 8 Steps to Lock Down Linux

Harden your production Linux server with eight practical security steps—SSH keys, firewall rules, fail2ban, and automatic updates that stop attacks before they start.

Written by Abdul AbrorTechnical Hosting Support Engineer
Server Security Checklist: 8 Steps to Lock Down Linux
On this page

Every day attackers scan the internet for weak servers. I've seen production boxes compromised in under 24 hours because someone skipped basic hardening. The good news? Most attacks fail against a properly configured Linux server.

This checklist covers eight security steps I apply to every production server. They're not exotic. They work because they address the attacks that actually happen—brute force SSH attempts, open ports, unpatched services, and privilege escalation. Each step takes minutes to implement and blocks entire categories of threats.

1. Disable root SSH login

Root login over SSH is the first thing attackers try. Every bot on the internet knows the username is "root"; they just need the password. Disable it.

Edit /etc/ssh/sshd_config and set:

PermitRootLogin no

Restart SSH:

sudo systemctl restart sshd

Create a regular user with sudo privileges instead. That way you authenticate as yourname, then elevate to root only when needed. Two-factor complexity for attackers; one extra command for you.

I make this change before anything else. It cuts automated attacks in half immediately.

2. Use SSH key authentication only

Passwords can be brute-forced. Keys cannot, practically speaking. Generate an SSH key pair on your local machine if you haven't already:

ssh-keygen -t ed25519 -C "[email protected]"

Copy the public key to your server:

ssh-copy-id username@your-server-ip

Test that key login works. Then disable password authentication entirely in /etc/ssh/sshd_config:

PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM no

Restart SSH again. Now attackers need your private key, which isn't sitting on the server and can't be guessed in a trillion years.

A side benefit: no more typing passwords. Your workflow gets faster while security improves.

3. Change the default SSH port

Port 22 gets hammered by automated scanners. Moving SSH to a non-standard port—say, 2222 or something above 1024—drops that noise to nearly zero.

In /etc/ssh/sshd_config, change:

Port 2222

Restart SSH. Update your firewall rules (covered next) to allow the new port. Connect with:

ssh -p 2222 username@your-server-ip

Yes, this is security by obscurity. It won't stop a determined attacker who port-scans you specifically. But it stops the bots, and bots are 99% of SSH attacks. Your logs will thank you.

4. Configure a firewall with minimal open ports

Most services don't need to be internet-facing. Lock everything down by default, then open only what you need.

On Debian/Ubuntu, use ufw:

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 2222/tcp   # your SSH port
sudo ufw allow 80/tcp     # HTTP
sudo ufw allow 443/tcp    # HTTPS
sudo ufw enable

On RHEL/CentOS/Rocky/AlmaLinux, use firewalld:

sudo firewall-cmd --set-default-zone=public
sudo firewall-cmd --permanent --add-port=2222/tcp
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload

Check what's listening:

sudo ss -tulnp

Anything listening on 0.0.0.0 that isn't explicitly needed should be reconfigured to bind to localhost or turned off. Database ports (3306, 5432) almost never need public exposure. Bind them to 127.0.0.1 in their config files.

Firewalls are simple. Default deny, explicit allow. That's it.

5. Install and configure fail2ban

Even with SSH keys and a non-standard port, you'll still see login attempts. Fail2ban watches your logs and bans IPs that fail authentication too many times.

Install it:

# Debian/Ubuntu
sudo apt install fail2ban

# RHEL/CentOS/Rocky/AlmaLinux
sudo dnf install fail2ban

Create a local config file at /etc/fail2ban/jail.local:

[DEFAULT]
bantime  = 3600
findtime = 600
maxretry = 5

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

Adjust port to match your SSH port. On RHEL-based systems, logpath is usually /var/log/secure.

Restart fail2ban:

sudo systemctl enable fail2ban
sudo systemctl restart fail2ban

Check banned IPs:

sudo fail2ban-client status sshd

Fail2ban also protects other services. You can enable jails for Apache, Nginx, Postfix, and more. Start with SSH; add others as needed.

6. Enable automatic security updates

Unpatched software is how servers get owned. Exploit code for known CVEs is public and automated. You can't rely on manual updates.

On Debian/Ubuntu, install unattended-upgrades:

sudo apt install unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades

Edit /etc/apt/apt.conf.d/50unattended-upgrades to enable automatic reboots if needed:

Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "03:00";

On RHEL/CentOS/Rocky/AlmaLinux, use dnf-automatic:

sudo dnf install dnf-automatic
sudo systemctl enable --now dnf-automatic.timer

Edit /etc/dnf/automatic.conf and set:

apply_updates = yes

Automatic updates carry a small risk of breaking something. That risk is microscopic compared to running a server with month-old vulnerabilities. If uptime is that critical, use a staging server to test updates first, or schedule a maintenance window weekly.

I've run automatic updates on production servers for years. Breaking changes are rare, and when they happen they're fixable. Compromises are not.

7. Disable unused services and remove unnecessary packages

Every running service is a potential attack surface. Most default installs come with services you'll never use.

List all running services:

sudo systemctl list-units --type=service --state=running

Disable anything you don't recognize or need. Common candidates:

sudo systemctl disable --now avahi-daemon
sudo systemctl disable --now cups
sudo systemctl disable --now bluetooth

Remove packages you didn't install intentionally:

# Debian/Ubuntu
sudo apt autoremove

# RHEL/CentOS/Rocky/AlmaLinux
sudo dnf autoremove

On a web server, you probably need a web server, a database, maybe PHP or Node. You don't need a print server, Bluetooth stack, or desktop search indexer. Strip them out.

Less code running means fewer bugs and smaller update surface. Keep it lean.

8. Configure basic intrusion detection

Intrusion detection won't stop an attack, but it tells you when something's wrong. For most use cases, file integrity monitoring is enough.

Install aide (Advanced Intrusion Detection Environment):

# Debian/Ubuntu
sudo apt install aide

# RHEL/CentOS/Rocky/AlmaLinux
sudo dnf install aide

Initialize the database:

sudo aideinit
sudo mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db

Run a check:

sudo aide --check

Schedule daily checks via cron:

sudo crontab -e

Add:

0 2 * * * /usr/bin/aide --check | mail -s "AIDE Report" [email protected]

AIDE watches system files for unauthorized changes. If an attacker modifies /etc/passwd or drops a rootkit, you'll know. It won't prevent the attack, but you'll detect it before it spreads.

For higher-stakes environments, consider OSSEC or Wazuh. They're heavier but offer real-time monitoring, log analysis, and active response. For a typical web server, AIDE is enough.

What about application-layer security?

This checklist focuses on the operating system and SSH layer. Your applications need their own hardening—disabling directory listing in Apache, setting secure headers in Nginx, parameterized queries in your database layer, rate limiting APIs.

Those are app-specific. The steps above apply to any Linux server, regardless of what you're running on top.

How often should you audit these settings?

After initial setup, quarterly audits are enough. Check that fail2ban is running, firewall rules haven't drifted, updates are still automatic, and no new services appeared. Automate the checks if you manage multiple servers.

I keep a script that SSH's into each box, runs the status commands, and emails me a summary. Takes five minutes to write, saves hours of manual checks.

Start with SSH and firewall

If you do nothing else, lock down SSH and configure a firewall. Those two steps block the majority of opportunistic attacks. The rest of this checklist builds defense in depth—multiple layers so that if one fails, the others hold.

Security isn't a one-time task. Review these settings when you spin up a new server, after major updates, or when something feels off. Most compromises I've investigated could have been stopped by this checklist. The steps are boring, but they work.

FAQ

Do I really need to change the SSH port?

No, but it's low-effort, high-impact for cutting bot noise. If your logs are full of failed root login attempts on port 22, moving SSH to another port will quiet them instantly. It's not a replacement for key-based auth—do both.

Can I use a different firewall instead of ufw or firewalld?

Yes. iptables directly, nftables, or cloud provider security groups all work. The principle stays the same: deny by default, allow explicitly.

What if automatic updates break something?

Test updates on a staging server first, or schedule a maintenance window and apply updates manually. But leaving a server unpatched is worse. Pick your risk.

How do I know if fail2ban is working?

Check the jail status with sudo fail2ban-client status sshd. You'll see banned IPs if any have triggered the rule. You can also tail the fail2ban log at /var/log/fail2ban.log.

Should I install an antivirus on Linux?

For a server? No. Focus on hardening, patching, and monitoring. Traditional antivirus doesn't add much value on a well-maintained Linux system. Rootkit detection (rkhunter, chkrootkit) can be useful for peace of mind, but it's secondary to the steps above.