Linux server hardening checklist (2026 edition)
There are a hundred Linux hardening checklists online and most of them are the same forty bullet points in a different order. We have read them. We also harden production servers for clients every week, and the gap between a checklist and a hardened box is judgment: which items actually stop attacks, which order to do them in, and which ones are security theater you can skip. So this is the checklist we work from, sorted by what stops the most damage for the least effort.
One assumption up front: this is for a fresh Linux server you control, Ubuntu or Debian flavored, that will run real services exposed to the internet. The commands are examples, not gospel; adapt paths and package names to your distro.
The five that stop most attacks
If you only ever do five things to a new server, do these. In our incident work, the boxes that get popped almost always skipped one of them, usually the first two.
- Log in with an SSH key and turn off password authentication entirely.
- Disable direct root login over SSH.
- Put a default-deny firewall in front of everything and open only the ports you actually use.
- Turn on automatic security updates so patches land without you remembering.
- Create a normal user with sudo and stop using root for daily work.
That is not a complete security program. It is the 20 percent that blocks the automated, low-effort attacks that make up the overwhelming majority of what hits a public IP. Bots are not clever; they scan for password logins and unpatched services and move on when they do not find them. The rest of this list is about the attacker who actually targets you, which is a much smaller group.
SSH is the front door, so lock it properly
Almost every server compromise we clean up came in through SSH or an unpatched web app. SSH first. Generate a key on your machine, copy the public half to the server, then test that key login works before you change anything else. Lock yourself out at this step and you are buying a console session from your provider, so keep a second terminal open.
Once the key works, edit /etc/ssh/sshd_config and set PasswordAuthentication no, PermitRootLogin no, and PubkeyAuthentication yes. Reload with systemctl reload sshd. That single change ends credential-stuffing against your server, because there is no password to guess anymore.
People love to argue about changing the SSH port off 22. We will be blunt: moving to port 2222 is not security, it is noise reduction. It keeps your logs cleaner because dumb scanners only hit 22, but anyone running a real port scan finds you in seconds. Do it if you like quieter logs. Do not do it and then feel safe.
A firewall is not optional
Default-deny inbound is the rule. On Ubuntu, UFW is the path of least resistance: ufw default deny incoming, ufw default allow outgoing, then ufw allow OpenSSH and a rule for each service you actually serve. Enable it with ufw enable and confirm SSH is allowed before you do, for the same lock-yourself-out reason as above.
The mistake we see most often is not the absence of a firewall, it is a firewall with a dozen leftover “allow” rules from things that got installed and removed months ago. Every open port is an entry you are responsible for patching. Audit the rule list quarterly and close anything you cannot explain in one sentence.
Patching is boring and it is most of the job
Staying patched beats almost every clever hardening trick, and nobody finds that exciting. A server running last year’s OpenSSH or an old kernel with a public exploit is vulnerable no matter how clever your firewall rules are. On Debian and Ubuntu, install unattended-upgrades and let it apply security updates on its own. Set it to email you on failures so a stuck upgrade does not sit quietly for a month.
Reboots are the part people dodge. Kernel and library patches do not fully take effect until the process or the box restarts. We schedule a maintenance reboot window for client servers and use needrestart to flag which services are still running old code in memory. If you never reboot, you are patched on disk and exposed in RAM.
Slow the brute force down
With password login already off, brute force against SSH is mostly a non-issue, but you still have web logins, mail auth, and other services. Fail2ban watches your logs and temporarily bans IPs that fail too many times. It is simple, it has worked for fifteen years, and it covers the common cases out of the box.
We have started using CrowdSec on newer client builds instead, because it shares attack signals across a community feed, so an IP that hammered someone else last hour can be blocked on your box before it tries. Both are fine. If you want set-and-forget, fail2ban. If you want a system that learns from attacks on other servers, CrowdSec. Do not run both fighting over the same log.
What we check after the basics
Once the front door is locked, the patches are flowing, and the firewall is tight, the returns get smaller but still matter for a server holding anything sensitive. Layering a web application firewall belongs in this pass, and choosing between ModSecurity and Imunify360 is a decision on its own. This is the second pass we run on a client box:
- Turn on the audit daemon (
auditd) so you have a record of who did what when something does go wrong. - Ship logs off the box to somewhere an attacker cannot edit them, because the first thing a competent intruder does is clean the local logs.
- Tighten a few kernel settings in
sysctl: disable IP source routing, enable reverse-path filtering, ignore broadcast pings. - Remove packages and services you do not use. The smallest attack surface is the software that is not installed.
- Set up file integrity monitoring (AIDE or similar) if the server holds data worth tampering with.
None of these stop the automated attacks the first five already handled. They are about detection and limiting blast radius when a real attacker gets a foothold, which is a different and harder problem.
The hardening theater we skip
Some checklist items get copied around because they sound serious, not because they help. We skip or deprioritize these, and we will tell a client why rather than padding an invoice with them. Changing the SSH port, as covered, is noise reduction not security. Disabling ping often breaks your own monitoring for no real gain. Forcing 30-day password rotation on the human accounts mostly produces sticky notes and weaker passwords, which is why modern guidance from NIST moved away from it years ago. Installing a heavyweight host IDS on a single small VPS usually generates alerts nobody reads. Effort is finite. Spend it on the five that matter and the second pass, not on items that look good in a screenshot.
The short version to keep
Strip everything above down and the working checklist is: SSH keys only, no root login, default-deny firewall, automatic security updates with scheduled reboots, a non-root sudo user, fail2ban or CrowdSec, then audit logging and a trimmed package list. Do the first five on day one. Do the rest in the first week. Re-audit the firewall and the user list every quarter.
If you would rather hand this off, hardening servers is a chunk of what we do. And when a hardened box still falls over, we run a server crash post-mortem to find out why. We run the full pass on a new box, document exactly what we changed and why, and leave you the checklist so your team can keep it tight. See our Linux server security and hardening service, or the wider website and server security services if your stack is bigger than one machine.
Before you harden a box, it helps to pick the right one. We break down the AWS option against a standard rented server in AWS Lightsail vs a $5 VPS.
Once the box is hardened, wire up cron-based Slack alerts so you hear about disk or service trouble before your visitors do. The same alerting is what warns you before a Let’s Encrypt renewal quietly fails and the cert expires under you.
Patched software is half the battle, and an application left on an unsupported release undoes the rest. Drupal 9 is a common example now that it is end of life; see our five-step Drupal 9 to 10 upgrade.
Unattended upgrades, log rotation and the backup job all need a scheduler behind them, and the choice is not automatic. We set out where we still use crontab and where we move a job over in our comparison of systemd timers and cron.
Next in the journal
- 30 Jun 2026 WordPress backup strategies that actually save you Almost everyone we get an emergency call from has backups. That is the cruel part. The site is down, the database is corrupt, the…
- 30 Jun 2026 Hosted email vs self-hosted in 2026 “Should we run our own email server or just pay for it?” We get asked this every few months, usually by a technical founder…