How to Harden a Linux Server for Beginners (2026)

Hardening a Linux server means cutting down what an attacker can reach: patch it, stop logging in as root, use SSH keys instead of passwords, put a firewall in front of it, and shut off services you never installed. Follow these steps in order on a Debian or Ubuntu server and you can finish in an afternoon.

Nobody breaks into a server by exploiting some exotic flaw on day one. A freshly provisioned box gets scanned within minutes of going live, and automated bots will try thousands of SSH password guesses against a default configuration. Most of the work below removes those easy targets, and every command is meant to be typed and then checked before you move on.

The commands are written for Debian and Ubuntu first, with the RHEL and CentOS equivalents called out where they differ. All of it is current as of 2026.

Table of Contents

What You Need

What You Need

You need root or sudo access, a working SSH session, and a way back in that does not depend on SSH. That last part is the one beginners skip, and it is the reason people end up locked out of their own server mid-change.

  • Root or sudo access on a Debian 11+ or Ubuntu 22.04+ server. Older releases reach end of support and stop receiving security patches.
  • A recent backup, or a provider snapshot. On most clouds this takes a minute and is your undo button.
  • A tested SSH session already open from your own machine, plus a second session you keep open for the whole process.
  • Console access through the provider’s web console, VNC, or serial console. This is your way in if SSH stops working.
  • The server’s public IP and the cloud firewall rules above it, if any. A cloud firewall can block you just as easily as ufw.
  • A text editor comfortable over SSH. nano is fine and is installed on both families.

The rule that saves you: never make a remote-access change and then close the session you are using. Change, open a second window, log in again, confirm it works, and only then close the first window.

How to Harden a Linux Server for Beginners: Step-by-Step

Work through these in sequence, and verify each one before continuing. Each step assumes the previous one held, so if a login stops working you know exactly which change caused it.

1. Create a Recovery Plan and Back Up the Server

Record what you have before you touch anything. Take a snapshot through your provider’s control panel, and confirm your backup actually restores rather than merely existing.

Then write down the current access configuration so you can compare later:

sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
ip -brief address
sudo systemctl status ssh

If this is a fresh VPS with nothing on it yet, a snapshot is enough. If it runs a database or customer data, verify the restore path first. Log out of nothing yet, and confirm the provider console opens on your own before moving on.

2. Apply All Operating System and Package Updates

Patching first means the fixes you rely on in later steps are actually in place. On Debian and Ubuntu:

sudo apt update
sudo apt upgrade -y
sudo apt autoremove -y

On RHEL, CentOS Stream, AlmaLinux and Rocky:

sudo dnf upgrade -y

Kernel updates only take effect after a reboot, so check whether one is pending rather than rebooting on a whim:

sudo apt install -y needrestart
sudo needrestart -r
sudo dnf install -y dnf-utils
sudo dnf needs-restarting -r

If it reports a reboot is needed, schedule one during a quiet moment and reconnect afterward. A kernel update that never gets loaded is just a download.

3. Create a Non-Root Administrative User and Use Least Privilege

Day-to-day work belongs in a normal account that uses sudo for the occasional privileged command. Root gets used for recovery, not for typing all day.

sudo adduser sysadmin
sudo usermod -aG sudo sysadmin

On RHEL family systems:

sudo useradd -m sysadmin
sudo passwd sysadmin
sudo usermod -aG wheel sysadmin

Now install your SSH public key on that account before doing anything else, so you are never relying on a password:

ssh-copy-id sysadmin@your-server-ip
ssh sysadmin@your-server-ip
sudo -l

That last pair confirms both the key login and that the account can escalate. Do not disable root yet. Learnlinux.tv forum regulars make exactly this point: root login is already off on some VPS images and on by default on others, so check your own settings instead of assuming.

4. Protect SSH with Keys, Restricted Login Settings, and a Firewall

SSH keys, then switch off password authentication, then reload sshd, then verify from a second window. This order is what keeps you from locking yourself out.

Generate a key if you do not have one, using the modern default type:

ssh-keygen -t ed25519
ssh-copy-id -i ~/.ssh/id_ed25519.pub sysadmin@your-server-ip

Back up /etc/ssh/sshd_config, then edit it:

sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
sudo nano /etc/ssh/sshd_config

Set these directives:

PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
PermitEmptyPasswords no
MaxAuthTries 3
X11Forwarding no
AllowUsers sysadmin

Check the syntax before you reload, because a broken config stops sshd from starting at all:

sudo sshd -t
sudo systemctl reload ssh

Then leave your current session alone and test from a second terminal. Only close the old window once the new login succeeds. If you lock out anyway, the provider console gets you in with your snapshot or backup sshd_config.

Changing the SSH port is defense in depth, not a real fix. It shrinks the log of automated scanners and nothing more, so do it only after keys work, and note the new port in your own notes.

5. Enable and Configure a Host Firewall

Allow SSH first, then enable the firewall, because the default deny rule blocks your own login. On Ubuntu with ufw:

sudo apt install -y ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw enable
sudo ufw status verbose

Add each service you actually run, by name where ufw has a profile:

sudo ufw allow 'Nginx Full'
sudo ufw allow 5432/tcp
sudo ufw reload

If you block yourself, the escape hatch is quick over a provider console: sudo ufw reset. Debian servers without ufw use nftables instead, where the same idea means a table with an input chain policy of drop and an explicit accept for tcp dport 22.

TaskUbuntu and DebianRHEL, CentOS, AlmaLinux
Install firewallsudo apt install ufwsudo dnf install firewalld
Allow SSH before enablingsudo ufw allow OpenSSHsudo firewall-cmd –permanent –add-service=ssh
Enable itsudo ufw enablesudo systemctl enable –now firewalld
Show rulessudo ufw status verbosesudo firewall-cmd –list-all
Start over after a mistakesudo ufw resetsudo firewall-cmd –panic-off

6. Remove Unneeded Services and Close Unused Network Ports

Every listening port is a door, and the useful question is whether you still own the thing behind it. Inventory first:

sudo ss -tulpen
sudo systemctl list-units --type=service --state=running

Go down the list and decide for each entry: do I use this, and do I know what it is? Names you cannot explain are the ones to investigate, not delete blindly.

Turn off what you do not need, which stops it starting at boot:

sudo systemctl disable --now service-name
sudo systemctl mask service-name

Disabling keeps the unit on disk; masking stops it being started at all, even by a dependency, which is the stronger option for something you are certain you do not need. When the package itself is unnecessary, remove it too:

sudo apt remove --purge package-name
sudo dnf remove package-name

Then re-run sudo ss -tulpen and confirm the ports you meant to close are gone and the ones you need are still listening.

7. Configure Secure Shell, Password, and File Permissions

Even with SSH keys on, local accounts still need real passwords. Set a quality policy that rejects short or common ones:

sudo apt install -y libpam-pwquality
sudo nano /etc/security/pwquality.conf
minlen = 14
minclass = 3

Lock the accounts nobody uses, so a stale service account cannot be logged into:

sudo usermod -L unused-account
sudo passwd -l unused-account

Keep the SSH configuration readable only by root, since it decides who gets in:

sudo chmod 600 /etc/ssh/sshd_config
ls -l /etc/ssh/sshd_config

One warning about /tmp: it should stay 1777 with the sticky bit set. Tightening it to 755 or 700 is a popular and wrong hardening tip that breaks package installs and applications in confusing ways.

8. Enable Automatic Security Updates and Central Logging

Manual updates stop happening. On Ubuntu, unattended-upgrades applies security patches on a schedule:

sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades

On RHEL family systems, dnf-automatic does the same job with a timer. Keep an eye on the logs either way, since silent patching can quietly break a service.

Make sure logging is actually running, because you will want these records later:

systemctl status systemd-journald
sudo journalctl -u ssh --since today
sudo tail -n 50 /var/log/auth.log

Sending logs off the machine to a central collector matters if you get compromised, since an attacker can clear local files. Logging is evidence, not a backup. Your snapshot is the backup.

9. Test the Hardened Server and Keep Monitoring It

Run this checklist after any hardening change, and again after a big update. Proof beats assumption.

  • SSH settings took effect: sudo sshd -T | grep -E 'permitrootlogin|passwordauthentication|maxauthtries' shows the values you set.
  • Key login works from a fresh terminal, and the sudo user can escalate with sudo -l.
  • Firewall rules are what you intended: sudo ufw status verbose, plus your provider’s cloud firewall rules.
  • Only expected ports are listening: compare sudo ss -tulpen against the list you saved in step 1.
  • No pending security work: re-run the update command and the reboot check.
  • Authentication logs look normal: no sudden burst of failed SSH attempts from unfamiliar addresses.
  • An external scan confirms it: from your own machine, nmap -sV your-server-ip shows only the ports you meant to publish.

For a broader second opinion, lynis audits a host against hundreds of practical checks:

sudo apt install -y lynis
sudo lynis audit system

Read the warnings rather than chasing a perfect score. Lynis flags plenty of settings that would break a real workload.

Common Mistakes

Almost every hardening disaster traces back to one of these, and each has a straightforward fix.

Editing sshd_config and reloading in the same breath. If the syntax is wrong, sshd may refuse to start and your next login fails. Fix: run sudo sshd -t, reload rather than restart, and keep the current session open while you test a second one.

Enabling the firewall before allowing SSH. The default deny rule then blocks your own port. Fix: sudo ufw allow OpenSSH first, then enable. Recovery: sudo ufw reset from the provider console.

Changing five things and then testing. When something breaks you have no idea which change caused it. Fix: one change, one verification, then move on.

Switching off updates permanently because a patch broke something. That trades one bug for a growing list of known exploits. Fix: pin or hold the specific package that misbehaved and keep taking everything else.

Living in a root shell all day. Every command runs with total privilege, and mistakes are unrecoverable. Fix: work as your sudo user and escalate per command.

Exposing ports you never opened yourself. A database or admin panel listening publicly gets found by scanners even when the password is strong. Fix: keep those bound to localhost or a private network, and reach them over an SSH tunnel.

Treating the firewall as the whole plan. A firewall does not patch software, restrict file permissions, or stop a compromised account. Fix: keep the full sequence, including updates, keys, and logging.

Frequently Asked Questions

Is changing the default SSH port worth it for a beginner?

Mostly no, and it is not a substitute for keys. Moving SSH to another port only shrinks the pile of automated scanners that hit port 22; an attacker who knows your real port finds it in seconds. It is worth doing as one layer after key authentication works, because it also cuts the noise in your logs. What actually stops brute-force logins is PasswordAuthentication no with keys only.

How do I recover if I lock myself out of my Linux server?

Use your provider’s web console, VNC or serial console, which sign in as root outside SSH. From there restore the config file you saved, for example sudo cp /etc/ssh/sshd_config.bak /etc/ssh/sshd_config, then reload ssh. If the firewall is the culprit, run sudo ufw reset. If nothing works, rebuild from the snapshot you took before starting.

Should I use Fail2ban if I already disabled SSH password logins?

Fail2ban is much less urgent once password authentication is off, because a key cannot be guessed. It still has value: it cuts log noise, blocks noisy scanners outright, and protects any password login you keep for a service account or an emergency. Many administrators run both. Start with keys first, then add Fail2ban for the remaining log volume.

What is the difference between ufw and firewalld?

Both are front ends for the same netfilter packet filter. Ubuntu ships ufw, which is simpler and defaults to deny incoming with a small allow list. RHEL, CentOS, AlmaLinux and Rocky ship firewalld, which uses zones and services and integrates with NetworkManager. Either is fine. Just use the one your distribution ships instead of installing a second firewall alongside it.

How do I check which ports my Linux server has open?

Run sudo ss -tulpen to list listening TCP and UDP sockets with the process name and user behind each one. For a web server you normally expect 22 for SSH, 80 for HTTP and 443 for HTTPS, plus whatever your application needs. Anything you cannot identify is worth investigating. Check from outside too, with nmap -sV against your server IP, because the view from the internet can differ.

How often should I update and re-check a hardened server?

Apply security updates weekly at minimum, and check for pending reboots at the same time. Re-run your verification checklist after every major update, since a kernel upgrade or a new package can open a port or reset a service. Do a full lynis audit a few times a year, and read the authentication logs regularly rather than only when something breaks.

Conclusion

If you only remember one sequence, use this one: take a snapshot and confirm console access, apply every pending update, create a non-root sudo user and prove its key login works, then harden sshd_config, then allow SSH before enabling the firewall. After that, inventory the listening ports and shut off what you do not use.

That is most of a Linux server hardening checklist for a beginner, and an afternoon of work. Then run the verification list, and re-run it after every update that matters. Security is a setting you maintain, not a state you reach once.

Leave a Comment