Skip to content
Back to Blog
Security11 min read

Server Security Hardening Checklist: 12 Configs [2026]

Lock down SSH, firewall rules, and running services with these 12 sysadmin-tested configurations that close the attack vectors exploited most often.

Written by Abdul AbrorTechnical Hosting Support Engineer
Server Security Hardening Checklist: 12 Configs [2026]
On this page

Every VPS lands on the internet with defaults that assume a private network and a friendly admin. The reality? Bots scan your IP within minutes of provisioning, hammering SSH, probing open ports, and brute-forcing root.

I've seen servers owned in under 48 hours because the admin never touched sshd_config or left Telnet running. This checklist covers the twelve configuration changes that close the attack vectors exploited most often—no fluff, just the exact edits and commands.

Why defaults leave you exposed

Out-of-the-box Linux distributions ship with:

  • SSH listening on port 22 with password auth enabled
  • Services you never use (rpcbind, Avahi, cups) bound to all interfaces
  • Permissive file permissions on system binaries
  • No rate-limiting on login attempts

These choices optimize for ease-of-setup, not defense. A hardened box flips every one.

1. Disable root SSH login entirely

Root over SSH is the single highest-value target. Even with a strong password, you're one zero-day or leaked key away from total compromise.

Edit /etc/ssh/sshd_config:

PermitRootLogin no

Restart the daemon:

systemctl restart sshd

From now on, log in as a regular user with sudo rights. If you haven't created that user yet, do it before you restart sshd or you'll lock yourself out.

2. Enforce public-key authentication only

Password authentication is guessable. Key authentication is not.

In the same config file:

PasswordAuthentication no
ChallengeResponseAuthentication no
PubkeyAuthentication yes

Before you apply this, verify your public key is in ~/.ssh/authorized_keys on the server and that you can log in with it. Test in a second terminal session so you don't close your only route in.

3. Change the SSH port (optional but effective)

Port 22 gets hit by every scanner on the planet. Moving SSH to a high port (say, 2849) drops brute-force noise by ninety percent.

Port 2849

Update your firewall rules to allow the new port and restart sshd. Remember to use -p 2849 in your ssh client from now on.

4. Limit SSH to specific users or groups

If only two accounts need SSH access, say so explicitly:

AllowUsers alice bob

Or restrict by group:

AllowGroups sshusers

Everyone else is denied, even if they have valid credentials.

5. Set a short idle timeout

An idle SSH session is a forgotten session. Close it automatically:

ClientAliveInterval 300
ClientAliveCountMax 2

This sends a keepalive every five minutes. After two unanswered keepalives, the session is killed. Adjust the interval to match your workflow.

6. Install and configure a firewall (iptables or firewalld)

A listening service can't be exploited if the firewall drops packets before they arrive.

Using UFW (simpler)

apt install ufw
ufw default deny incoming
ufw default allow outgoing
ufw allow 2849/tcp  # your SSH port
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable

Using iptables directly

iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp --dport 2849 -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
iptables-save > /etc/iptables/rules.v4

Make the rules persistent with iptables-persistent on Debian/Ubuntu or firewalld on RHEL/CentOS.

7. Disable unused services

Every daemon is attack surface. List what's running:

systemctl list-unit-files --type=service --state=enabled

Common candidates for disablement:

  • rpcbind (unless you run NFS)
  • avahi-daemon (unless you need mDNS/Bonjour)
  • cups (printing service, irrelevant on a headless server)
  • bluetooth (if present)

Disable them:

systemctl disable --now rpcbind
systemctl disable --now avahi-daemon
systemctl disable --now cups

Reboot and verify they stayed off.

8. Tighten file permissions on critical binaries

Some distros leave world-writable permissions on cron directories or allow any user to read shadow files. Fix the obvious ones:

chmod 700 /root
chmod 600 /etc/ssh/sshd_config
chmod 644 /etc/passwd
chmod 600 /etc/shadow
chmod 600 /etc/gshadow
chmod 700 /var/log/audit

Run find / -perm -002 -type f 2>/dev/null to hunt for world-writable files. Anything in /bin, /sbin, /usr/bin, or /usr/sbin should not be writable by others.

9. Enable automatic security updates

Patching is not optional. On Debian/Ubuntu:

apt install unattended-upgrades
dpkg-reconfigure -plow 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, dnf-automatic does the same job.

10. Install and configure fail2ban

Fail2ban watches logs for repeated failures and bans offending IPs via iptables.

apt install fail2ban
cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

Edit jail.local:

[sshd]
enabled = true
port = 2849
maxretry = 3
bantime = 3600

Restart:

systemctl enable --now fail2ban

Check banned IPs:

fail2ban-client status sshd

In support tickets I handled, this single change cut brute-force attempts visible in auth.log by over half.

11. Restrict kernel parameters with sysctl

The kernel itself has tunables that resist network attacks. Create /etc/sysctl.d/99-hardening.conf:

# Ignore ICMP redirects
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0

# Ignore source-routed packets
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0

# Enable TCP SYN cookies (anti-DDoS)
net.ipv4.tcp_syncookies = 1

# Log martian packets
net.ipv4.conf.all.log_martians = 1

# Ignore broadcast pings
net.ipv4.icmp_echo_ignore_broadcasts = 1

# Disable IP forwarding (unless you're a router)
net.ipv4.ip_forward = 0
net.ipv6.conf.all.forwarding = 0

Apply:

sysctl -p /etc/sysctl.d/99-hardening.conf

These settings won't break normal traffic but will deflect certain spoofing and redirect attacks.

12. Audit with Lynis or OpenSCAP

Once you've made changes, verify them. Lynis is a command-line auditing tool:

wget -O - https://packages.cisofy.com/keys/cisofy-software-public.key | apt-key add -
echo "deb https://packages.cisofy.com/community/lynis/deb/ stable main" > /etc/apt/sources.list.d/cisofy-lynis.list
apt update
apt install lynis
lynis audit system

Review the report in /var/log/lynis.log. It will flag weak permissions, enabled services, missing compiler restrictions, and kernel parameters you forgot.

OpenSCAP does similar work for compliance frameworks (CIS, STIG). Install openscap-scanner and run a benchmark relevant to your distro.

What about containers and cloud?

These twelve configs assume a traditional VPS or bare-metal box. Containers inherit the host kernel, so harden the host with these same steps and then apply least-privilege principles inside the container (non-root user, read-only filesystems, dropped capabilities).

Cloud instances often come with security groups or network ACLs that act as external firewalls. Use them, but still configure iptables or ufw on the instance itself—defense in depth means two layers are better than one.

Common mistakes I see

  • Changing the SSH port but forgetting to update the firewall, locking yourself out.
  • Disabling password auth before confirming key auth works.
  • Running fail2ban with default jails that don't match your actual SSH port.
  • Setting PermitRootLogin without-password instead of no—the former still allows key-based root login.

Test every change in a staging environment or keep a console session open through your hosting provider's web VNC before you close your SSH window.

How long does hardening take?

For a fresh server, thirty to forty-five minutes if you're typing commands by hand. Automate it with Ansible or a shell script and you'll cut that to under five.

The payoff? Logs that aren't flooded with brute-force noise, services that can't be reached by attackers, and one less 3 a.m. phone call about a compromised box.

What if I inherit a server that was never hardened?

Start with SSH and the firewall—those two give you the biggest immediate win. Then audit running services and disable what you don't recognize. Save kernel tuning and fail2ban for after the critical stuff is locked down.

Does moving SSH off port 22 actually help?

It won't stop a determined attacker who port-scans your entire range, but it eliminates the constant background noise from bots that only probe 22. Your auth logs become readable again.

Can I lock down SSH and still use password auth for one account?

Yes, with Match User blocks in sshd_config, but that adds complexity and a wider attack surface. Key auth for everyone is simpler and stronger.

How often should I re-audit?

After every major software update and at least quarterly. New vulnerabilities appear; your config drifts. A quarterly Lynis run catches the drift.

What to check first

If you only have ten minutes, hit these three:

  1. Disable root SSH login and enforce key auth.
  2. Enable a firewall that drops everything except SSH, HTTP, and HTTPS.
  3. Disable services you don't use.

Those three close the majority of the holes that get exploited in the first week after a server goes live. The rest of the checklist hardens what's left, but start with the big wins.