News
🐧 Linux Tutorials Harden a Fresh Linux Server: First 10 Steps

Harden a Fresh Linux Server: First 10 Steps

The actions that matter most in the first hour after provisioning a new server — before it gets hammered by bots and before something goes wrong.

A fresh server is exposed the moment it gets a public IP. Bots start probing within minutes. These ten steps cover the basics that apply to virtually any Linux server running in a public environment, regardless of what it is eventually going to do.


1 — Log in and update immediately

Before anything else:

sudo apt update && sudo apt upgrade -y    # Debian / Ubuntu
sudo dnf upgrade -y                        # RHEL / Fedora / Rocky

Distribution packages ship with known CVEs fixed in recent updates. Running old packages on a new server means starting with known vulnerabilities.


2 — Create a non-root user

Running everything as root means a single mistake — a bad script, a compromised service — has unlimited blast radius.

adduser deploy
usermod -aG sudo deploy     # Debian / Ubuntu
usermod -aG wheel deploy    # RHEL / Fedora

Log out, log back in as the new user, and confirm sudo works before closing the root session.


3 — Set up SSH key authentication

Passwords are brute-forceable. Keys are not.

On your local machine, generate a key if you do not have one:

ssh-keygen -t ed25519 -C "your-laptop"

Copy the public key to the server:

ssh-copy-id deploy@your-server-ip

Test that key login works — keep your current session open as insurance — then continue to step 4. The full walkthrough for this step is in the SSH Key Authentication tutorial.


4 — Disable password authentication

Only do this after confirming key login works from every machine that needs access.

Edit /etc/ssh/sshd_config:

PasswordAuthentication no
PermitRootLogin no
PubkeyAuthentication yes

On Ubuntu, also check for overrides in /etc/ssh/sshd_config.d/:

sudo grep -r PasswordAuthentication /etc/ssh/

If a file in sshd_config.d/ sets it back to yes, edit that file too. Then reload:

sudo systemctl reload ssh    # Debian / Ubuntu
sudo systemctl reload sshd   # RHEL / Fedora

Open a new terminal and confirm that password login is rejected before closing the existing session.


5 — Configure a firewall

Allow only the ports you actually need. Everything else should be closed.

UFW (Debian / Ubuntu — easiest):

sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status

firewalld (RHEL / Fedora):

sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload

Do not enable the firewall before allowing SSH, or you will lock yourself out.


6 — Install fail2ban

fail2ban watches auth logs and bans IPs that fail authentication too many times.

sudo apt install fail2ban    # Debian / Ubuntu
sudo dnf install fail2ban    # RHEL / Fedora

The default configuration already monitors SSH. Enable and start it:

sudo systemctl enable --now fail2ban

Check that it is running and watching sshd:

sudo fail2ban-client status sshd

The default is 5 failed attempts before a 10-minute ban. That is enough to stop automated brute-force tools cold.


7 — Change the SSH port (optional, debated)

Moving SSH off port 22 is not a security measure — any port scanner finds it in seconds. But it does eliminate the constant noise of automated bots in your auth logs, which makes it easier to spot real login attempts.

In /etc/ssh/sshd_config:

Port 2222

If you do this, update your firewall rules before reloading sshd:

sudo ufw allow 2222/tcp
sudo ufw delete allow OpenSSH
sudo systemctl reload ssh

And update your fail2ban configuration to watch the new port if necessary.


8 — Keep automatic security updates on

Manual updates get skipped. Automate at least the security patches:

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

On RHEL-based systems:

sudo dnf install dnf-automatic
sudo systemctl enable --now dnf-automatic.timer

This applies security fixes automatically. It will not handle major version upgrades or non-security packages, so you still need to review and apply those manually.


9 — Disable unused services

Every service running is an attack surface. Check what is listening:

ss -tulnp

Disable anything you recognise but do not need:

sudo systemctl disable --now avahi-daemon
sudo systemctl disable --now cups

The specifics depend on the distribution and what was installed. A minimal server image usually has this under control already. A full desktop image installed on a VPS often has several services running that have no business being on a server.


10 — Set up log monitoring

You do not need to read logs manually, but something should alert you if authentication failures spike or a critical service dies.

At minimum, check in periodically:

sudo journalctl -u ssh --since "1 hour ago"
sudo last | head -20
sudo lastb | head -20     # failed login attempts

lastb is the most useful — it shows every failed login attempt with the username tried, the source IP, and the timestamp. After running fail2ban for a few days, you will see the same IP ranges hitting the same common usernames (root, admin, ubuntu, test) on rotation. That is the background noise. Anything that looks targeted — your actual username, attempts from a specific IP you recognise — is worth investigating.


Checklist

  • System packages updated
  • Non-root user created, sudo access confirmed
  • SSH key authentication set up and tested
  • Password auth disabled, root login disabled
  • Firewall enabled with minimal open ports
  • fail2ban installed and monitoring SSH
  • Automatic security updates configured
  • Unused services disabled