TL;DR
Harden a new Linux server in this order: create a non-root user with sudo, set up SSH key authentication and disable password + root login, put a UFW firewall in front of everything, install Fail2ban to block brute-force attempts, turn on automatic security updates, and finish with a Lynis audit to score what you missed. That covers the attacks that actually hit internet-facing servers. Everything below is copy-paste, tested on Debian/Ubuntu (the commands map cleanly to most distros).
The first time I stood up a VPS on a public IP and tailed the auth log, I watched bots try to log in as root within about ninety seconds. They never stop. Automated scanners sweep the entire IPv4 space constantly, and a default server with password login is a door left open on a busy street.
The good news: the baseline that stops the overwhelming majority of those attacks is short, boring, and takes under an hour. This guide is that baseline. It is the same sequence I run whether the box is a cloud VPS, a home lab machine, or the Raspberry Pi pentest box I leave on networks. Do these steps in order, because a couple of them lock the door behind you and you want a working key in hand first.
Step 0: Update everything first
Before hardening anything, patch the software you already have. Unpatched packages are the single most common way a server gets compromised, and no firewall rule saves you from a known hole in a service you're running.
On a RHEL/Fedora box that's sudo dnf upgrade --refresh. Reboot if the kernel was updated (sudo reboot). Patching isn't a one-time task, which is why Step 6 automates it.
Step 1: Create a non-root sudo user
Working as root full-time means one fat-fingered command or one compromised session owns the whole machine. Create a normal user, give it sudo for the occasional admin task, and stop logging in as root entirely.
On RHEL-family systems the admin group is wheel instead of sudo. Now open a new terminal, SSH in as that user, and run sudo whoami — if it prints root, your sudo access works and you can stop using the root account.
Step 2: Set up SSH key authentication
Passwords can be guessed, phished, and brute-forced. An SSH key can't be typed, so it can't be brute-forced. This is the single highest-impact change on the list. Generate a key on your own machine, not the server.
ed25519 is the modern default — short, fast, and strong. Give the key a passphrase when prompted; that way a stolen laptop doesn't hand over your servers. ssh-copy-id installs the public key into the server's ~/.ssh/authorized_keys for you. Now test it:
Step 3: Harden the SSH server
SSH is the front door and the most-attacked service on any Linux box, so it earns the most attention. Edit the config:
Set these four directives (uncomment or add them):
That disables root login over SSH, turns off password auth (keys only), and closes the keyboard-interactive fallback that some setups leave open. Apply it by reloading the service:
Step 4: Set up a firewall (UFW)
A firewall enforces a simple rule: only the ports you explicitly opened are reachable, everything else is dropped. Any service you forgot you were running is now invisible from the internet. UFW (Uncomplicated Firewall) is the friendly front-end to iptables/nftables on Debian and Ubuntu.
Add sudo ufw allow 80/tcp and sudo ufw allow 443/tcp only if this box actually serves web traffic. The principle is deny everything, then allow the short list you need — not the other way around.
allow OpenSSH line above has to run before enable, or the firewall will drop your own connection the moment it turns on. If you changed the SSH port, use sudo ufw allow <port>/tcp instead of the OpenSSH profile.Step 5: Block brute-force attempts with Fail2ban
Even with keys-only SSH, bots will keep hammering the port. Fail2ban watches your logs and temporarily bans any IP that fails to authenticate too many times, so the noise stops and a slow credential-stuffing attack has nowhere to go.
Always edit jail.local, never jail.conf — the .conf gets overwritten on package updates. Open jail.local and, in the [sshd] section, make sure the jail is on:
Then start it and check the jail is watching:
Give it a day and run that last command again — you'll see a list of banned IPs, which is a quietly satisfying look at how much unwanted attention a public server gets.
Step 6: Turn on automatic security updates
Step 0 patched the server once. This makes it stay patched without you remembering to. On Debian/Ubuntu, unattended-upgrades installs security fixes on its own.
Answer "Yes" to the prompt. By default it applies only security updates, which is exactly what you want on a server — low risk of a breaking change, no unpatched holes sitting for weeks. For anything that needs a reboot to take effect (a new kernel), schedule a maintenance window rather than letting it reboot unattended on a production box.
Step 7: Audit your work with Lynis
Now grade what you did. Lynis is an open-source auditing tool that scans a system against a long list of hardening checks and prints a score plus concrete suggestions. It is the fastest way to catch the things a checklist misses.
Lynis prints color-coded findings as it goes and ends with a hardening index (a score out of 100) and a list of suggestions with IDs. Don't chase a perfect 100 — some suggestions won't apply to your use case. Read each one, apply the ones that make sense, and re-run to watch the score climb. It's already installed on Kali, so it doubles as a recon tool when you're auditing a box from the other side.
A few things beyond the baseline
The seven steps above stop the attacks that actually hit internet-facing servers. Once they're in place, the next layer depends on what the box does:
Shared responsibility with your provider. On a cloud VPS, set up the provider's network firewall (AWS security groups, DigitalOcean cloud firewalls) in addition to UFW — defence in depth, and it protects you even if the host firewall is misconfigured. Minimise what's installed. Every running service is attack surface; uninstall what you don't use and run sudo ss -tulpn to see exactly what's listening. Back up before you need to. Hardening reduces the odds of compromise; backups are what save you when something gets through anyway.
If you're coming at this from the offensive side — learning what these defences look like from an attacker's seat — the recon tools in my top 10 Kali Linux tools guide and the nmap walkthrough are the other half of the picture. Hardening a box and then scanning it yourself is the fastest way to understand why each step matters.
Frequently Asked Questions
What is the single most important step?
Switching SSH to key-only authentication and disabling password login (Steps 2 and 3). Passwords are what automated bots attack; a key removes that entire attack class. If you only had time for one change, it would be this one.
Do these commands work on CentOS/RHEL/Fedora?
The concepts are identical; a few commands differ. Use dnf instead of apt, the wheel group instead of sudo, and firewalld (or install UFW) instead of Debian's default. SSH hardening, Fail2ban, and Lynis all work the same way.
Is changing the SSH port worth it?
It reduces log noise from low-effort bots, but it's obscurity, not security — a real scanner finds the new port immediately. Do it if quieter logs help you, but never in place of keys, a firewall, and Fail2ban.
Will automatic updates break my server?
Unattended-upgrades applies only security updates by default, which rarely change behaviour. The one thing to control manually is reboots — a kernel update needs a reboot to take effect, so schedule that yourself on a production box rather than letting it happen unattended.
How often should I re-audit with Lynis?
After every significant change, and on a routine schedule (monthly is reasonable). Keep the reports so you can compare them — a rising hardening index means you're improving, and new suggestions flag drift or newly installed services that widened your attack surface.
