Server Hardening
Every article in this module covered one control in depth: least privilege as a principle, sudo and PAM as the authentication and privilege-escalation layer, SELinux/AppArmor as mandatory access control, firewalls as the network boundary, fail2ban and auditd as detection. None of them, on its own, is "server hardening" — hardening is the discipline of applying all of them, in a sensible order, to one concrete server, plus a handful of items that don't have their own dedicated article: removing what isn't needed, automating patching, and verifying the result. This closing article is that checklist.
What You Will Learn
By the end of this article you will be able to:
- explain why hardening steps need to be applied and verified in order, not all at once;
- reduce a server's package and service footprint to what it actually needs;
- configure automatic security updates and know what they don't cover;
- apply a handful of kernel-level (
sysctl) hardening settings and explain what each does; - use
lynisto get an independent, automated second opinion on a server's hardening state.
Why Order Matters
A hardening pass touches authentication, the firewall, and system services all at once if done carelessly — and any one of those, misapplied, can lock out the very session doing the work. The safe sequence mirrors the "confirm before the next irreversible step" pattern used throughout this course:
- confirm remote access works and has a fallback (a console session independent of SSH, if the server is remote);
- reduce the package and service footprint;
- lock down authentication (SSH, sudo, PAM, password policy);
- apply mandatory access control;
- apply the firewall, SSH access confirmed first;
- add detection (fail2ban, auditd, log review);
- automate patching;
- verify the whole result independently.
Each numbered step below links to the article that covers it in depth — this article's job is the ordering and the items that don't belong anywhere else.
Step 1: Confirm a Fallback Before Touching Anything
Before any other step, confirm there's a way back onto the server that doesn't depend on the change about to be made — a hosting provider's console access, or a second, already-open SSH session kept alive throughout the entire hardening pass. Every destructive-adjacent step below (ufw enable, a PAM change, an SSH config reload) repeats this same warning in its own article; stated once here, it applies to the whole checklist, not just one step in it.
Step 2: Reduce the Footprint
The single cheapest hardening step, and the one most often skipped, is removing what a server doesn't need at all — Linux Security Fundamentals introduced this as attack surface reduction.
A MySQL server listening on 0.0.0.0:3306 on a host where only local applications should ever reach the database is worth questioning immediately — either it should bind to 127.0.0.1 only, or the firewall rule for it should never have allowed access from outside the application subnet in the first place (see Firewall and UFW).
bluetooth and cups (printing) enabled on a headless server are leftovers from a default install, not requirements — each one is a running daemon with its own attack surface and no legitimate purpose on this machine:
autoremove --purge clears packages that were only installed as dependencies of something already removed, along with their configuration files — a smaller installed footprint is fewer packages that could, in principle, ever need a security patch.
Step 3: Lock Down Authentication
This is where most of the module's earlier articles apply directly, in this order:
- SSH — key-only authentication, no root login, restricted
AllowUsers— see SSH Hardening, which already covers the full checklist and the safe rollout order. - sudo — scoped rules, no blanket
NOPASSWD: ALL, I/O logging for sensitive accounts — see sudo Security. - PAM —
pam_faillockenabled,nullokremoved frompam_unix— see PAM Basics and Root and sudo. - Password policy — complexity, history, and expiration set deliberately rather than left at distribution defaults — see Password Policies.
No new commands here — the point of listing them together is the order: authentication needs to be solid before the firewall and MAC layers go on top of it, since those two protect a system whose authentication is assumed to already be trustworthy.
Step 4: Apply Mandatory Access Control
Confirm SELinux or AppArmor is actually enforcing, not merely installed:
A server with SELinux installed but left in Permissive, or AppArmor's profiles left in complain, gets the logging benefit of MAC without the blocking benefit — worth checking explicitly, since a Permissive system otherwise looks identical to an Enforcing one in every command that doesn't specifically check the mode. SELinux and AppArmor covers switching modes safely and building profiles for anything not already covered by the default policy.
Step 5: Apply the Firewall
sudo ufw allow 22/tcp # or the confirmed alternate SSH port
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw enable
As covered in Firewall and UFW, the SSH allow rule must exist and be confirmed before ufw enable runs, not after — repeated here because it's the step most likely to end a hardening session with a locked-out server if done out of order.
Step 6: Add Detection
fail2ban and auditd Basics cover configuring each in depth; the hardening checklist's job is simply confirming both are actually running, since a service that's installed but not enabled provides no protection at all — a mistake easy to make when a package installs a daemon but leaves it disabled by default.
Step 7: Automate Patching
Production Updates already covers unattended-upgrades in full — a hardened server that never receives security patches is hardened against yesterday's vulnerabilities only:
Automatic patching is not automatic verification
unattended-upgrades applies security patches; it does not confirm services restart correctly afterward, and it does not cover major version upgrades. Production Updates covers needrestart, the tool that closes exactly this gap — a patched-but-not-restarted service is still running the vulnerable code in memory.
A Few Items With No Article of Their Own
Two small, standalone hardening items don't warrant a full article but belong on any checklist:
A login banner, displayed before authentication, stating that access is monitored and unauthorized use is prohibited — a legal and deterrent measure in many jurisdictions and organizational policies, not a technical control:
Kernel network hardening via sysctl, a small set of settings worth enabling on any internet-facing server:
net.ipv4.tcp_syncookies = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.icmp_echo_ignore_broadcasts = 1
tcp_syncookiesmitigates a SYN-flood by allowing the kernel to handle a connection backlog without keeping full state for each half-open connection;accept_redirects = 0andaccept_source_route = 0refuse ICMP redirects and source-routed packets, both of which can otherwise be abused to reroute this host's traffic through an attacker-controlled path;icmp_echo_ignore_broadcastsprevents the host from participating in a Smurf-style amplification attack.
net.ipv4.tcp_syncookies = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.icmp_echo_ignore_broadcasts = 1
Step 8: Verify Independently with lynis
After applying the checklist by hand, an independent audit tool provides a second opinion that doesn't share the blind spots of whoever just did the hardening:
[+] System Tools
------------------------------------
- Scanning available tools...
- Checking present vendor and tools...
[+] Kernel
------------------------------------
- Checking default run level [ RUNLEVEL 5 ]
- Checking CPU support (NX/PAE) [ FOUND ]
...
Hardening index : 68 [############ ]
Warning: Access to audit log is not restricted
Suggestion: Consider hardening SSH configuration [CIS-CAT: 5.2.11]
lynis doesn't fix anything itself — it inspects the system's actual configuration against a large set of known hardening benchmarks and reports a score alongside specific, actionable suggestions. The score itself matters less than the specific list of suggestions underneath it; treating "get to 100" as the goal, rather than reviewing each suggestion on its own merits for this specific server, produces the same box-checking failure mode covered in Linux Security Fundamentals — a high score is not proof of security, only evidence that the tool's specific checks currently pass.
Practical Scenario: Hardening a Fresh Ubuntu Server LTS Before Production
Problem. A newly provisioned Ubuntu Server LTS instance needs to go from default install to production-ready.
Following the checklist in order:
# Step 1: fallback already confirmed — provider console access verified before starting
# Step 2: footprint
sudo systemctl list-unit-files --state=enabled | grep -v -E 'ssh|systemd|cron|networkd|resolved'
sudo apt autoremove --purge
# Step 3: authentication (see linked articles for full detail)
# SSH keys confirmed, PasswordAuthentication no, sudoers scoped, pam_faillock enabled
# Step 4: MAC
aa-status | head -n 3
# Step 5: firewall — SSH confirmed first
sudo ufw allow 22/tcp
sudo ufw enable
# Step 6: detection
sudo systemctl enable --now fail2ban auditd
# Step 7: patching
sudo dpkg-reconfigure --priority=low unattended-upgrades
# Step 8: verify
sudo lynis audit system
Result. lynis's hardening index rises from a fresh-install baseline (typically in the 50s) into the high 70s or 80s after the checklist is applied, and its remaining suggestions become the input for the next iteration rather than a one-time pass.
Conclusion. No single step here was new — every command traces back to an article already covered in this module or an earlier one. The value of this final article is the order and the completeness of the list, not any individual technique.
Common Mistakes
- Applying every hardening step at once, without testing between them. As emphasized throughout this module, a mistake in any one step (a bad PAM line, an enabled firewall with no SSH rule) is far easier to isolate and fix when steps are applied and verified one at a time.
- Hardening authentication and the firewall but skipping the footprint reduction step. A server with fewer running services simply has less that needs to be hardened in the first place — skipping this step means every later step has more surface to cover.
- Treating a
lynisscore as the finish line. As covered above, the score is a rough signal; the specific list of suggestions, evaluated against what this particular server actually needs, is the part that matters. - Enabling
unattended-upgradesand assuming patching is now fully automated. Reboots for kernel updates and service restarts after a library update, covered in Production Updates, still require an active process, not just the package's default configuration. - Running the checklist once at provisioning time and never again. Permission Audit and this module's overall message both apply here — a server hardened once and never revisited drifts back toward its unhardened default over time.
Exercises
- On a lab VM, run through steps 2 (footprint reduction) and 8 (
lynis) only, note the hardening index, then apply steps 3 through 7 and re-runlynis. Compare the two scores and identify which specific suggestions disappeared. - Explain why the order in this checklist puts footprint reduction before firewall configuration, rather than the other way around.
- Pick three
lynissuggestions from a real scan and, for each, decide whether it's worth applying to a specific server you have in mind, explaining your reasoning either way. - Write the single sentence you would want the person taking over this server from you to read first, summarizing the state of its hardening and what still needs attention.
Summary
Server hardening is not a distinct technique — it's the disciplined, ordered application of every control this module covered: reduce the footprint, lock down authentication, apply mandatory access control, apply the firewall with access confirmed first, add detection, automate patching, and verify the result independently with a tool like lynis. The order matters because each step can otherwise interfere with — or lock you out of — the next, and the process itself needs to repeat on a schedule, not run once at provisioning and be forgotten.