A Server Hardening Checklist
A fresh server install is a soft target. Hardening closes the gap between default settings and a defensible baseline.
Defaults are convenient, not secure
Every server ships configured for the broadest possible compatibility, which is the opposite of secure. Hardening is the disciplined process of removing what you do not need, locking down what you do, and making sure that when something goes wrong you will know. This is a practical checklist for hardening a Linux server — the order matters, because each layer assumes the one before it is in place. None of it is exotic; the value is in doing all of it, consistently, on every server.
Start with access: the front door
The most common path to a compromised server is weak remote access, so fix that first.
- Disable root login over SSH and disable password authentication entirely — use SSH keys only. This single change eliminates the entire category of brute-force credential attacks.
- Create a dedicated admin user with sudo rights, so actions are attributable and root stays unused.
- Change nothing security-by-obscurity-only, but do consider moving SSH off port 22 to cut log noise from automated scanners.
- Enforce key passphrases and an idle timeout so an unlocked laptop does not equal an open session forever.
Reduce the attack surface
Every running service is a potential way in. A hardened server runs only what it needs and nothing else.
- Audit listening ports and stop or remove services you are not deliberately using.
- Uninstall unused packages — compilers, legacy daemons, sample apps — rather than leaving them dormant.
- Configure a host firewall to deny by default and allow only the specific inbound ports the server's role requires.
The principle is simple: you cannot exploit what is not there. Each package removed is one fewer thing to patch, monitor, and worry about.
Patch, and keep patching
An unpatched server is the most reliably exploited system on the internet, because attackers automate against known vulnerabilities the moment they are disclosed. Enable automatic security updates for the operating system, and establish a cadence for the updates that need a human — kernel upgrades, application versions, anything requiring a restart. The goal is that no known critical vulnerability sits unpatched for longer than your agreed window. Pair this with a record of what is installed so you can answer "are we affected?" quickly when the next advisory lands.
Enforce least privilege everywhere
Beyond user accounts, apply least privilege to the whole system. Services should run as unprivileged users scoped to exactly what they need, never as root. File permissions should be tight, especially on configuration files holding secrets. Where the platform supports it, mandatory access control like SELinux or AppArmor confines a compromised process so it cannot reach the rest of the system. The aim throughout is to shrink the blast radius: if one component is breached, the damage stops there.
Make sure you would actually know
Hardening that you cannot observe is half a job. Centralise logs off the server so an attacker cannot simply erase their tracks, and alert on the events that matter — failed logins in bursts, privilege escalation, changes to critical files, new listening ports. Time-sync every server so logs from different systems line up during an investigation. The test is honest and simple: if this server were compromised tonight, what would tell you, and how soon?
Make hardening repeatable, not a one-off
A server hardened by hand and then forgotten drifts back toward insecurity as people make undocumented changes over months. The durable answer is to make the baseline code. Capture your hardening steps in a configuration management tool or a documented build script so every new server starts compliant and any drift is detected and corrected automatically. This turns hardening from a manual ritual you might skip under deadline pressure into a property of the platform itself.
- Define the baseline once as code, then apply it identically to every server you stand up.
- Re-run the configuration regularly so a server that has drifted is pulled back into line without anyone remembering to check.
- Version the baseline, so when a new requirement appears you update one definition and it propagates everywhere.
Consistency is itself a security property: a fleet where every server is configured the same way is one you can reason about, audit quickly, and trust.
Validate the work, then keep validating
Hardening you have not verified is an assumption, and assumptions are exactly what attackers exploit. After applying the baseline, scan the server with a vulnerability scanner to confirm the gaps you intended to close are actually closed, and benchmark the configuration against a recognised standard so you are measuring against an external yardstick rather than your own memory. Then schedule that check to repeat, because new vulnerabilities surface constantly and a server hardened last year is not necessarily hardened today. Treat validation as an ongoing rhythm, not a milestone you pass once and forget.
How BSH can help
BSH Technologies hardens servers as part of our managed IT and cybersecurity work — applying a consistent baseline across your fleet as code, automating patching, validating against recognised standards, and wiring logging and alerting so nothing slips by silently. We can audit existing servers against this checklist and remediate the gaps, or build hardened images for everything you deploy next. If your servers are running on defaults, let's change that.
From the blog
View all postsDesigning Multi-Tenant SaaS That Scales
Choosing an isolation model, keeping tenant data separate, and dodging the noisy-neighbour and migration traps that bite SaaS later.
Hitting Green Core Web Vitals in Next.js
A practical guide to LCP, INP and CLS in Next.js — image handling, font loading, the App Router boundary, and costly third-party scripts.