Linux runs a large share of the world’s infrastructure: web servers, databases, cloud instances, and the containers stacked on top of them. That ubiquity makes it a high-value target. The default configuration of a fresh install is tuned for getting things working, not for keeping attackers out. Linux server hardening is the process of systematically shrinking that attack surface: removing what the server does not need, locking down what remains, and keeping it in that state as the system changes. This linux server hardening guide walks the full process with the actual commands. It covers stripping packages and closing ports through SSH, auditd, and kernel-level access control, then ends on the part most guides skip: confirming the hardening held.
What Linux Server Hardening Involves
Hardening a Linux server is not one action, it is a set of deliberate configuration choices across every layer an attacker can touch. That work spans operating system configuration, service and package management, and user accounts and authentication. It also covers network and firewall rules, SSH, kernel-level controls, and the application-specific settings of whatever the server runs.
The distinction that matters most is that this is applied at deployment and maintained continuously, not set once. The reference standard most Linux hardening programs build on is the CIS Benchmark for the specific distribution in use. It is prescriptive down to the individual setting and revised as the distribution changes. Everything in this guide maps back to that idea: a documented target state, applied and then verified.
Three Core Principles That Drive Every Linux Hardening Decision

Before the commands, three principles explain why each hardening decision exists. They apply to hardening Linux servers of every role, from a web host to a database box that also needs database hardening. Every specific decision in this guide follows from one of them.
Remove Everything That Is Not Required
Distributions ship broad, covering every use case someone might have. Your server has one job. A hardened server runs only what that job requires. Every extra package, service, and utility is more code that can hold a vulnerability or a misconfiguration. The priority order is strict: removal beats disabling, and disabling beats leaving something running with no plan for it. Code that is not installed cannot be exploited.
Apply Secure Settings to Everything That Remains
What survives the cut still ships insecure. Defaults are chosen for compatibility and first-boot usability, not for minimal exposure. SSH is the clearest example: a stock sshd_config permits things no production server should, and tightening it is a required step, not an optional one. Every service that stays gets configured against the standard rather than left at its shipped defaults.
Maintain the Secure State Over Time
Hardening decays. Updates rewrite config files, operational shortcuts loosen settings under deadline pressure, and new software arrives with its own permissive defaults. A server hardened at deployment and never re-checked can drift meaningfully within weeks. This is why linux server security hardening is a practice rather than a project, with scheduled re-audits and drift detection. It is the principle the final section of this guide is built around.
Step 1: Remove Unnecessary Packages and Disable Unused Services
Start by seeing what is actually on the box. Inventory the installed packages and the running services, then remove or disable anything the server’s role does not require.
List installed packages by package manager. On RHEL, CentOS, and Fedora:
rpm -qa | sort
On Debian and Ubuntu:
dpkg -l | sort
Then list what is actually running:
systemctl list-units --type=service --state=running
For each service that does not belong, stop and disable it. Stopping alone is not enough, because a merely stopped service restarts on the next boot. Disabling is what makes it stick:
systemctl disable --now <service>
Work through the running set deliberately. A print service, an exposed RPC daemon, or a mail transfer agent nobody uses is attack surface you get to delete for free. When learning how to harden a Linux server, this step returns the most security per minute spent. Every service removed is one you never have to configure, patch, or audit again.
Step 2: Minimize Open Ports and Harden Network Configuration
Every open port is a door, and a door only helps you if the server’s role actually needs it open. List what is listening and which process owns it:
ss -tulpn
That gives you the protocol, the port, and the process. Cross-reference every listener against the server’s role. Anything you cannot justify traces back to a service from Step 1. Closing the port is usually a matter of stopping and disabling that service rather than filtering it at the firewall. Close the door by removing what stands behind it, then use the firewall to enforce the result.
Configure the Host-Based Firewall
Linux gives you two primary host-based firewall front ends: firewalld on RHEL-family systems and iptables, or its nftables backend, more broadly. Whichever you use, the model is the same and it is not optional: default-deny inbound. Block everything arriving by default, then explicitly permit only the ports the role requires.
With firewalld, setting the default zone to drop and opening a single required service looks like:
firewall-cmd --set-default-zone=drop firewall-cmd --permanent --add-service=https
The host-based firewall complements network-level controls, it does not replace them. A cloud security group and a host firewall are defense in depth. The host firewall is the one that still protects the server when something is already inside the network.
Disable Legacy Network Protocols
Turn off protocols the server does not use. Disable NetBIOS over TCP/IP where it is not required. Disable IPv6 if nothing on the server uses it, rather than leaving it configured and unwatched. Block ICMP echo where ping responses serve no operational purpose. Each disabled protocol is one less thing an attacker can probe or abuse, and one less subsystem you have to keep patched.
Step 3: Harden User Accounts and Authentication
Once an attacker has any foothold, your account and authentication configuration decides how far they get. Harden it as if the perimeter has already failed.
Password Policy Configuration
Set password quality in /etc/security/pwquality.conf and lockout behavior through PAM in /etc/pam.d/. The CIS-aligned targets are a minimum length of 14 characters, enforced complexity, account lockout after repeated failures, and strong hashing. Lockout is handled by pam_faillock, configured to lock after a small number of failed attempts and hold the lock for a set window:
deny=5 unlock_time=900
Ensure password hashing uses SHA-512 rather than any weaker legacy algorithm. These settings turn a stolen or guessed password from an open door into a slow, noisy, rate-limited problem for the attacker.
Remove Unnecessary User Accounts
Default installs carry service and shell accounts your specific server does not need. Review /etc/passwd, and remove or lock anything that is not operationally required. Service accounts that belong but should never be logged into interactively need a non-login shell. That way a stolen credential cannot open a session:
usermod -s /sbin/nologin <account>
An account that cannot log in interactively is one an attacker cannot use as a home base, even if they obtain its password.
Restrict sudo and Privilege Escalation
Root is not for routine administration. Configure /etc/sudoers, always through visudo, to grant each user or group only the specific commands their work requires, rather than a blanket ALL. Broad sudo rights are the difference between a compromised account that can do a little and one that can do everything. Then watch sudo usage in the audit log, so privilege escalation is recorded rather than invisible.
Step 4: SSH Hardening
SSH is the primary remote access path to a Linux server, which makes it the single most important service to harden. If you learn how to harden one Linux server service well, make it this one. Get this one wrong and much of the rest of your work is moot. The configuration lives in /etc/ssh/sshd_config, and changes take effect after a service restart with systemctl restart sshd.
The settings that matter most, and what each closes off:
Protocol 2only, retiring the broken version 1.PermitRootLogin no, so an attacker must compromise a named account and then escalate, rather than attacking root directly.PasswordAuthentication nowith key-based authentication instead, which ends password brute-forcing against SSH entirely.MaxAuthTries 4andLoginGraceTime 60, shrinking the window and attempt count per connection.PermitEmptyPasswords no, closing an obvious hole.X11Forwarding nowhere it is not needed, removing a lateral-movement aid.ClientAliveInterval 300withClientAliveCountMax 0, terminating idle sessions so an unattended terminal does not become an entry point.AllowUsersorAllowGroups, restricting SSH to the specific accounts that should ever connect.
Key-based authentication is the highest-value single change on this list. It removes the entire category of password-guessing attacks against your most exposed service. It is also the setting that most cleanly separates a hardened Linux server from a default one.
Step 5: Configure Audit Logging with auditd
Hardening without logging means an attacker who gets in leaves no trace, which turns an incident into an unanswerable question. Linux provides auditd as the system audit daemon. Enable it, then configure rules to capture the events that matter:
systemctl enable --now auditd
Write audit rules that record authentication events, privilege escalation, changes to account management files, and access to sensitive paths. A rule watching for changes to the password store looks like:
auditctl -w /etc/passwd -p wa -k passwd_changes
Configure log retention to meet whatever compliance regime applies to the system. In environments where log integrity and central visibility matter, ship the audit logs to a SIEM. Logs that live only on the audited host are the first thing an attacker clears after a compromise. Getting them off the box is part of the control, not an extra.
Step 6: Kernel Hardening with SELinux or AppArmor
Kernel-level security modules enforce mandatory access controls that constrain what a process can do even when it runs as root. This is the layer that contains a compromise: a web server exploited into running arbitrary code is still boxed into what its policy permits. Leaving it off removes your last line of defense, which is exactly why misconfigured systems so often have it disabled.
SELinux (RHEL, CentOS, Fedora)
SELinux enforces mandatory access controls on RHEL-family systems. Confirm it is set to enforcing mode in /etc/selinux/config (SELINUX=enforcing) and verify the running state:
getenforce
The important distinction is enforcing versus permissive. Permissive mode logs violations but does not block them, which is useful for troubleshooting and useless as protection. Enforcing is the only mode that actually contains anything, and every service should run within a controlled security context rather than an unconfined one.
AppArmor (Ubuntu, Debian)
AppArmor provides equivalent mandatory access control on Debian-based distributions, using path-based profiles. Check profile status:
aa-status
Ensure the profiles for your running services are in enforce mode rather than complain mode, which is AppArmor’s equivalent of permissive:
aa-enforce /etc/apparmor.d/<profile>
Both SELinux and AppArmor are frequently found disabled or left permissive on systems hardened in a hurry. They can require tuning to stop breaking a misbehaving application, and switching them off is the lazy shortcut. Doing that tuning, rather than switching the module off, is the difference between real containment and its appearance.
Linux Server Hardening Checklist Summary

This linux server hardening checklist is a scannable reference to the areas above, not a substitute for the detail in each step.
- Remove unnecessary packages and disable unused services.
- Close unused network ports and configure a default-deny firewall policy.
- Configure password complexity, lockout, and strong SHA-512 hashing.
- Remove or lock unnecessary user accounts and give service accounts a non-login shell.
- Disable direct root login and configure least-privilege sudo access.
- Harden SSH: Protocol 2, no root login, key-based authentication only, idle session timeout.
- Enable and configure auditd with appropriate rules and log retention.
- Enable SELinux in enforcing mode on RHEL-family systems, or AppArmor in enforce mode on Debian-based systems.
- Apply hardening settings to the application services running on the server.
- Re-audit the configuration on a schedule and monitor for drift.
These linux server hardening steps cover the configuration layer end to end, and together they form a practical baseline of linux server hardening best practices. The one thing a checklist cannot do is tell you whether the settings are still in place next month, which is the actual hard part.
Verify Your Linux Hardening Against a Benchmark with Panopsys
Applying these controls is the easy half. Confirming that dozens of settings across every server are correct is hard enough once. Keeping them correct as the systems change is impractical to do by hand at any real scale. That is the gap between a server you hardened and a server you can prove is hardened.
The Panopsys Hardening module closes it. It audits a Linux system against established hardening baselines, the same practices that recognized benchmark frameworks codify. Coverage spans Linux, Apache, Nginx, MySQL, and PostgreSQL, with 60+ control points on Linux alone. It runs as a script you download and read in full before it executes, using the system’s own native commands. Nothing is installed and nothing is left running afterward, so your team can audit the auditor before it touches production. Every control comes back compliant, non-compliant, or not applicable. Every gap is tied to the asset it was found on and prioritized by asset criticality, that is, by that asset’s real risk. Pair it with CVE Watch and both halves are covered: hardening closes the configuration gaps, and CVE Watch tracks the software vulnerabilities left in the packages running on your hardened system.


