Hardening Ubuntu Server 24.04 LTS - Basic Security Measures

Posted on November 4, 2025 (Last modified on November 5, 2025) • 11 min read • 2,218 words

Step-by-step guide to securing a freshly installed Ubuntu Server 24.04 LTS with firewall, Fail2Ban, and automatic updates

Hardening Ubuntu Server 24.04 LTS - Basic Security Measures
Photo by Growtika  on Unsplash 

Recently I rented a Cloud Virtual Private Server (VPS) with pre-installed Ubuntu Server 24.04 LTS. However, before installing the first services on it, the most important step always comes first: securing the system. An unsecured server on the internet is like an open door – it often takes only minutes before the first automated attack attempts start.

The steps described here apply equally if you operate a server in your homelab that is accessible from the internet. Whether cloud VPS or your own hardware – the fundamentals of hardening remain the same.

In this article, I’ll show you how to secure an Ubuntu Server 24.04 LTS with basic but effective security measures. We will go through the most important steps together that every server should undergo before being put into productive use.

Why Server Hardening is Important

Even in a private homelab, security should not be neglected. The reasons are manifold:

  • Automated Attacks: Bots constantly scan the internet for open ports and try to gain access
  • Data Privacy: Even private data deserves protection
  • Learning Effect: Implementing best practices improves your understanding of IT security
  • Prevents Abuse: A compromised server can be misused for spam, DDoS attacks, or crypto mining

Prerequisites

For this article you will need:

  • A freshly installed Ubuntu Server 24.04 LTS (Noble Numbat)
  • Root or sudo access to the server
  • SSH access to the server
  • Basic Linux knowledge
  • Optional: A second computer for external security tests

Step 1: Initial Assessment - Check for Exposed Ports

Before we start hardening, we should get an overview of which services are currently running and which ports are exposed to the outside. This is important to understand what we need to secure.

Local Port Check

The ss command (socket statistics) shows us all listening ports:

sudo ss -tulpn
Netid State  Recv-Q Send-Q Local Address:Port Peer Address:Port Process
tcp   LISTEN 0      128          0.0.0.0:22        0.0.0.0:*     users:(("sshd",pid=1234,fd=3))
tcp   LISTEN 0      128             [::]:22           [::]:*     users:(("sshd",pid=1234,fd=4))

Parameters explained:

  • -t = TCP connections
  • -u = UDP connections
  • -l = Only listening sockets
  • -p = Shows process information
  • -n = Numeric display (no name resolution)

In this example, we see that only SSH (port 22) is listening – a good starting point for a fresh server.

List Active Services

Let’s see which services are active on the system:

systemctl list-units --type=service --state=running
UNIT                        LOAD   ACTIVE SUB     DESCRIPTION
ssh.service                loaded active running OpenBSD Secure Shell server
systemd-journald.service   loaded active running Journal Service
systemd-udevd.service      loaded active running Rule-based Manager for Device Events

External Port Check (Optional)

If you have a second computer on the network, you can scan from the outside using nmap:

nmap -sV 192.168.1.100
Starting Nmap 7.94
Nmap scan report for homelab-srv (192.168.1.100)
Host is up (0.0012s latency).
Not shown: 999 closed ports
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 9.6p1 Ubuntu 3ubuntu13 (Ubuntu Linux; protocol 2.0)

Step 2: Update the System

The first and most important step is to bring the system up to date. Security updates close known vulnerabilities.

sudo apt update
Reading package lists... Done
Building dependency tree... Done
sudo apt upgrade -y
The following packages will be upgraded:
  base-files curl libcurl4 openssh-client openssh-server
5 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

If kernel updates were installed, a reboot is required:

sudo reboot

Step 3: Set Up UFW Firewall

UFW (Uncomplicated Firewall) is a user-friendly frontend solution for iptables. It allows us to quickly and easily define firewall rules.

Install and Configure UFW

sudo apt install ufw -y
sudo ufw allow 22/tcp comment 'SSH'
Rules updated
Rules updated (v6)

Set the default policy (block incoming connections, allow outgoing):

sudo ufw default deny incoming
sudo ufw default allow outgoing
Default incoming policy changed to 'deny'
Default outgoing policy changed to 'allow'

Enable the firewall:

sudo ufw enable
Firewall is active and enabled on system startup

Check the status:

sudo ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW IN    Anywhere                   # SSH
22/tcp (v6)                ALLOW IN    Anywhere (v6)              # SSH

Open Additional Ports for Services

Depending on your requirements, you can open additional ports. Here are some common examples:

 Web server
sudo ufw allow 80/tcp comment 'HTTP'
sudo ufw allow 443/tcp comment 'HTTPS'

 Docker Swarm (example)
 sudo ufw allow 2377/tcp comment 'Docker Swarm'

 Proxmox Web Interface (if needed)
 sudo ufw allow 8006/tcp comment 'Proxmox Web UI'

Step 4: User Management and sudo Rights

It’s a best practice not to work as root and to restrict sudo access. Important: We set this up BEFORE we harden SSH and disable root login to avoid locking ourselves out!

Create a New User (if not already present)

sudo adduser frank
Enter new password:
Retype new password:
Enter the full name []: Frank

Add User to sudo Group

sudo usermod -aG sudo frank

Verify sudo Access

sudo whoami
[sudo] password for frank:
root

Disable Root Account (Optional)

If you’re sure you no longer need root:

sudo passwd -l root
passwd: password expiry information changed

Step 5: Secure SSH

SSH is usually the only externally accessible service on a server. That’s why it’s particularly important to secure it well.

Use SSH Key Pairs

If you’re not already using SSH keys, first create a key pair on your local machine:

ssh-keygen -t ed25519 -C "homelab-server"
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/frank/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase): #### Enter password!
Your identification has been saved in /home/frank/.ssh/id_ed25519
Your public key has been saved in /home/frank/.ssh/id_ed25519.pub

Copy the public key to the server:

ssh-copy-id ubuntu@192.168.1.100
Number of key(s) added: 1

Now try logging into the machine, with: "ssh 'ubuntu@192.168.1.100'"

Test the login with the key:

ssh ubuntu@192.168.1.100
Welcome to Ubuntu 24.04 LTS (GNU/Linux 6.8.0-45-generic x86_64)

Harden SSH Configuration

Now let’s adjust the SSH configuration. First create a backup:

sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup

Edit the configuration:

sudo nano /etc/ssh/sshd_config

# Change port (optional but recommended)
Port 2222

# Only use SSH Protocol 2
Protocol 2

# Disable root login
PermitRootLogin no

# Disable password authentication (only after SSH key test!)
PasswordAuthentication no
PubkeyAuthentication yes

# Forbid empty passwords
PermitEmptyPasswords no

# Disable X11 forwarding (if not needed)
X11Forwarding no

# Limit MaxAuthTries
MaxAuthTries 3

# Reduce LoginGraceTime
LoginGraceTime 20

# Only allow specific users (optional)
AllowUsers ubuntu

# Only use IPv4 (optional)
AddressFamily inet

Check the configuration for syntax errors:

sudo sshd -t
# No output means: Everything OK!

Enable and restart the SSH service:

sudo systemctl enable ssh
sudo systemctl restart ssh.socket

Important: Open a second SSH connection to the server BEFORE you close the first one to ensure you can still log in!

Step 6: Install and Configure Fail2Ban

Fail2Ban monitors log files and automatically blocks IP addresses after repeated failed login attempts. This protects against brute-force attacks.

Installation

sudo apt install fail2ban -y

Configuration

Fail2Ban uses a jail.conf that we should not edit directly. Instead, we create a jail.local:

sudo nano /etc/fail2ban/jail.local

[DEFAULT]
# Ban time: 1 hour
bantime = 3600

# Time window in which attempts are counted: 10 minutes
findtime = 600

# Maximum number of failed attempts
maxretry = 5

# Ignore local IPs (adjust to your network)
ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24

[sshd]
enabled = true
port = 2222
# If you're using the standard port 22, change this accordingly
logpath = %(sshd_log)s
backend = %(sshd_backend)s

Start Fail2Ban and enable autostart:

sudo systemctl enable fail2ban
sudo systemctl start fail2ban

Check the status:

sudo fail2ban-client status
Status
|- Number of jail:      1
`- Jail list:   sshd

Details for a specific jail:

sudo fail2ban-client status sshd
Status for the jail: sshd
|- Filter
|  |- Currently failed: 0
|  |- Total failed:     0
|  `- File list:        /var/log/auth.log
`- Actions
   |- Currently banned: 0
   |- Total banned:     0
   `- Banned IP list:

Test Fail2Ban (Optional)

To test if Fail2Ban works, you can try logging in multiple times from another computer with a wrong password:

ssh ubuntu@192.168.1.100 -p 2222
ubuntu@192.168.1.100's password: #### Enter wrong password
Permission denied, please try again.
# After 5 attempts: Connection refused

The IP will now be blocked for 1 hour. You can check this:

sudo fail2ban-client status sshd
Status for the jail: sshd
|- Currently banned: 1
`- Banned IP list:   192.168.1.50

If you want to manually unblock an IP:

sudo fail2ban-client set sshd unbanip 192.168.1.50

Step 7: Set Up Automatic Security Updates

Security updates should be applied promptly. With unattended-upgrades we can automate this.

Installation

sudo apt install unattended-upgrades -y

Configuration

Edit the configuration file:

sudo nano /etc/apt/apt.conf.d/50unattended-upgrades

Unattended-Upgrade::Allowed-Origins {
    "${distro_id}:${distro_codename}";
    "${distro_id}:${distro_codename}-security";
    // Also install important updates (optional)
    // "${distro_id}:${distro_codename}-updates";
};

// Packages that should NOT be automatically updated
Unattended-Upgrade::Package-Blacklist {
    // Example: "docker-ce";
};

// Automatically reboot if necessary (caution in homelab!)
Unattended-Upgrade::Automatic-Reboot "false";

// If reboot enabled: set time
Unattended-Upgrade::Automatic-Reboot-Time "02:00";

// Email notification (optional)
// Unattended-Upgrade::Mail "your@email.com";
// Unattended-Upgrade::MailReport "on-change";

// Automatically remove old kernels
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
Unattended-Upgrade::Remove-Unused-Dependencies "true";

Enable automatic updates:

sudo dpkg-reconfigure -plow unattended-upgrades
# Select "Yes"

Check the configuration:

sudo unattended-upgrades --dry-run --debug

Step 8: Final Security Check

After implementing all measures, we’ll perform a final verification.

Check Open Ports Again

sudo ss -tulpn | grep LISTEN
tcp   LISTEN 0      128          0.0.0.0:2222      0.0.0.0:*     users:(("sshd",pid=1234,fd=3))

Perfect! Only our custom SSH port is still open.

Check UFW Status

sudo ufw status numbered
Status: active

     To                         Action      From
     --                         ------      ----
[ 1] 2222/tcp                   ALLOW IN    Anywhere                   # SSH custom port
[ 2] 2222/tcp (v6)              ALLOW IN    Anywhere (v6)              # SSH custom port

Check Fail2Ban Status

sudo systemctl status fail2ban
● fail2ban.service - Fail2Ban Service
     Loaded: loaded (/lib/systemd/system/fail2ban.service; enabled; preset: enabled)
     Active: active (running) since Mon 2025-11-04 10:15:32 UTC; 2h ago

External Port Check (if possible)

nmap -sV 192.168.1.100 -p 1-65535
Starting Nmap 7.94
Nmap scan report for homelab-srv (192.168.1.100)
Host is up (0.0012s latency).
Not shown: 65534 filtered ports
PORT     STATE SERVICE VERSION
2222/tcp open  ssh     OpenSSH 9.6p1 Ubuntu 3ubuntu13

Excellent! From the outside, only the custom SSH port is visible.

Check Login Attempts in the Logs

sudo tail -n 20 /var/log/auth.log
Nov  4 10:30:15 homelab-srv sshd[2456]: Accepted publickey for ubuntu from 192.168.1.50
Nov  4 10:30:15 homelab-srv sshd[2456]: pam_unix(sshd:session): session opened for user ubuntu

Additional Measures (Optional)

Depending on your requirements, you can take further security measures:

Check AppArmor Status

AppArmor (Application Armor) is a Mandatory Access Control (MAC) system that comes pre-installed with Ubuntu. It restricts the permissions of individual programs by confining them to security profiles. For example, a compromised web server can only access the files it really needs.

Ubuntu 24.04 comes with AppArmor pre-installed. Check if it’s active:

sudo aa-status
apparmor module is loaded.
49 profiles are loaded.
49 profiles are in enforce mode.

Automatic Security Audits with Lynis

Lynis is an open-source security audit tool that checks your system for vulnerabilities and configuration problems. It scans hundreds of security aspects (SSH configuration, firewall settings, kernel parameters, installed packages, etc.) and provides you with a detailed report with suggestions for improvement.

sudo apt install lynis -y
sudo lynis audit system
# Lynis performs a comprehensive security scan

Two-Factor Authentication for SSH (2FA)

For maximum security, you can set up 2FA with Google Authenticator:

sudo apt install libpam-google-authenticator -y
google-authenticator
# Follow the instructions and scan the QR code with your Authenticator app

Conclusion

Of course, IT security is an ongoing process. Regularly check the logs, keep the system updated, and adapt the security measures to your changing requirements.

Next Steps

Now that your server is secured, you can start installing your services. Here are some ideas:

  • Install Docker and Docker Compose
  • Set up a reverse proxy like Traefik or Nginx Proxy Manager
  • Set up monitoring tools like Prometheus and Grafana
  • Implement backup solutions

References


Have fun hardening your server and enjoy your homelab!