Ubuntu 22.04 Security Hardening: The First 30 Minutes on a New Server

A newly provisioned Ubuntu server arrives ready to use, but its default configuration leaves significant security gaps. SSH runs by default, network access is open, and the root account accepts password-based logins. That setup works well for quick testing, but it creates serious vulnerabilities on a production server exposed to the internet. Automated attacks target these defaults within minutes of a server going live.

The first thirty minutes on any new server shape its security posture for its entire lifespan. What you configure in that window determines whether the server begins its life hardened against common threats or exposed to them. This guide walks through the essential steps an IT specialist takes when setting up a new Ubuntu 22.04 server, working from the outside in to close the most common attack vectors.

Why the First Thirty Minutes Matter

Internet-facing servers face constant scanning and automated attacks. Bots continuously sweep IP ranges looking for open SSH ports with default or weak credentials. They try common username/password combinations, exploit known vulnerabilities in outdated packages, and probe for misconfigured services. A server that goes live with its default configuration rarely stays clean for more than a few hours.

Hardening a server immediately after provisioning prevents these automated attacks from succeeding. Each step in this guide removes or reduces a specific attack surface. Together, they create a meaningful barrier against the most common threats without requiring advanced technical knowledge.

If you are setting up a web server alongside these hardening steps, the UFW firewall configuration guide covers port rules for common web server scenarios in more detail.

Create a Standard User Account

Root access provides unrestricted control over the entire system. Logging in as root for daily administration is convenient, but it introduces unnecessary risk. A single mistyped command can damage critical system files. Logging in as root also means any compromised key or session has full system access.

Create a standard user account with sudo privileges for everyday administration tasks. This user can perform administrative actions when needed but operates with limited permissions by default.

adduser nick

usermod -aG sudo nick

After creating the user, set up SSH key authentication so password-based logins can be disabled. Generate an SSH key pair on your local machine if you have not already done so, then copy the public key to the server.

mkdir -p /home/nick/.ssh

chmod 700 /home/nick/.ssh

# Add your public key to the authorized_keys file on the server

nano /home/nick/.ssh/authorized_keys

chmod 600 /home/nick/.ssh/authorized_keys

chown -R nick:nick /home/nick/.ssh

Test that the new user can connect via SSH and execute sudo commands before closing the root session. If something goes wrong with the SSH configuration later, having a working sudo account gives you a path back in.

Configure the SSH Daemon

SSH is the primary entry point for any internet-accessible Linux server, and it is also the most targeted service. The default SSH configuration permits root login and password authentication, both of which create significant security risks. Automated bots attempt root logins with common passwords constantly.

Edit the SSH daemon configuration to restrict access:

sudo nano /etc/ssh/sshd_config

Set the following parameters in the configuration file:

PermitRootLogin no
PasswordAuthentication no
PermitEmptyPasswords no
X11Forwarding no
MaxAuthTries 3
ClientAliveInterval 300
ClientAliveCountMax 2

The MaxAuthTries 3 setting limits failed login attempts before the connection drops. ClientAliveInterval 300 keeps connections alive during idle periods, which prevents unexpected disconnections on slower networks.

Validate the configuration syntax before reloading the SSH service:

sudo sshd -t

If the configuration test returns errors, fix them before reloading. An invalid sshd_config combined with key-based-only authentication can lock you out of the server completely. Once the test passes, reload the SSH daemon:

sudo systemctl reload sshd

For a more detailed walkthrough of SSH hardening options, the guide to securing SSH on Ubuntu covers additional settings and explains each parameter in context.

Set Up a Basic Firewall with UFW

Ubuntu includes UFW (Uncomplicated Firewall), which provides a straightforward interface for managing netfilter rules. A default-deny policy blocks all incoming connections that are not explicitly permitted, creating a clean security baseline.

Configure UFW with the appropriate rules before enabling it:

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow http
sudo ufw allow https
sudo ufw enable

Warning: Enabling the firewall without allowing SSH first will drop your current connection if you are connected remotely. Always allow SSH before running ufw enable.

After enabling UFW, verify that your SSH session remains active and that the firewall is running:

sudo ufw status verbose

Servers running multiple services should open only the ports that are actually required. A database server accessed only by application servers on the same private network does not need to be reachable from the internet. Restricting access to only what is necessary reduces the attack surface considerably.

Keep the System Updated

Software vulnerabilities are discovered regularly, and security patches address them in updated packages. An unattended server with out-of-date packages accumulates known vulnerabilities over time. Configure automatic security updates to close this gap without requiring manual intervention.

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

The reconfiguration command presents an interactive prompt. Select "Yes" to enable automatic updates. Security updates should apply automatically. Other updates can be set to automatic with a notification sent to the administrator so you know what changed on the server.

Review the configuration file at /etc/apt/apt.conf.d/50unattended-upgrades to customise which updates are applied automatically and where notifications are sent.

Disable Unused Services

Every running service listening on the network represents a potential attack surface. A freshly provisioned server often starts with services that are not needed for its intended purpose. Reducing the number of running services limits the available attack vectors.

List all running services to identify what is active:

systemctl list-units --type=service --state=running

For each running service, determine whether it is necessary for the server's purpose. If a service is not needed, stop it and disable it so it does not start automatically after a reboot:

sudo systemctl stop service-name
sudo systemctl disable service-name

On a standalone web server, services that are commonly unnecessary include Bluetooth, Avahi (network discovery), CUPS (print services), and any mail services that do not serve the server's function. Review each service and make a deliberate decision rather than assuming the defaults are correct.

Protect Critical System Files

Setting the immutable flag on critical system binaries prevents accidental or malicious modification during normal operation. The chattr command sets attributes that go beyond standard Unix permissions.

Protect the chattr utility itself first, so it cannot be tampered with:

sudo chattr +i /usr/bin/chattr

Then apply protection to binaries that should never change during normal server operation:

sudo chattr +i /bin/chattr
sudo chattr +i /usr/bin/chmod
sudo chattr +i /usr/bin/sudo

Be careful with immutable flags. Files marked immutable cannot be modified even by root without first removing the flag. Keep a record of which files are protected so you can modify them during legitimate maintenance windows.

Protect the boot configuration to prevent unauthorised changes to bootloader parameters:

sudo chown root:root /etc/grub.d
sudo chmod 750 /etc/grub.d

For servers with physical access concerns, setting a GRUB password adds another layer of protection:

sudo grub-mkpasswd-pbkdf2

Add the generated password hash to /etc/grub.d/40_custom and update GRUB:

sudo update-grub

Harden the Kernel and Network Stack

Linux kernel parameters control how the operating system handles network connections, buffers, and potential attacks. Configuring these parameters appropriately improves the server's resilience against network-based threats.

Edit /etc/sysctl.conf to apply network hardening settings. Add or modify the following lines:

# Prevent IP spoofing
net.ipv4.conf.all.rp_filter = 1
net.ipv6.conf.all.rp_filter = 1

# Disable source packet routing
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0

# Ignore ICMP redirects
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0

# Disable send redirects
net.ipv4.conf.all.send_redirects = 0

# Enable SYN flood protection
net.ipv4.tcp_syncookies = 1

# Restrict ARP neighbour entries
net.ipv4.neigh.default.gc_thresh1 = 4096
net.ipv4.neigh.default.gc_thresh2 = 8192
net.ipv4.neigh.default.gc_thresh3 = 16384

Apply the changes immediately without rebooting:

sudo sysctl -p

Verify the settings were applied correctly:

sudo sysctl net.ipv4.tcp_syncookies
sudo sysctl net.ipv4.conf.all.accept_source_route

Fail2Ban: Automated Attack Mitigation

Fail2ban monitors log files for repeated failed login attempts and automatically updates firewall rules to block the offending IP address. This automated response handles brute-force attacks without manual intervention.

Install and enable Fail2ban:

sudo apt install fail2ban
sudo systemctl enable fail2ban
sudo systemctl start fail2ban

Create a local configuration file to override defaults:

sudo nano /etc/fail2ban/jail.local

Add SSH protection settings:

[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
findtime = 600

Restart Fail2ban to apply the configuration:

sudo systemctl restart fail2ban

Check the status of active bans:

sudo fail2ban-client status
sudo fail2ban-client status sshd

The Fail2ban setup guide covers additional configuration options including HTTP protection for web servers.

Disable Unused File Systems and Kernel Modules

Blocking unnecessary kernel modules reduces the attack surface by preventing unused functionality from being loaded. Edit the module blacklist configuration:

sudo nano /etc/modprobe.d/blacklist.conf

Add the following entries:

blacklist usb-storage
blacklist firewire-core
blacklist thunderbolt

These modules are rarely needed on a headless server and can be used to access system resources in certain attack scenarios. After updating the blacklist, regenerate the initramfs to ensure changes take effect at boot:

sudo update-initramfs -u

Set Up Log Monitoring and File Integrity

Logs only provide value if they are reviewed and managed. Configure logrotate to prevent log files from consuming all available disk space:

sudo nano /etc/logrotate.d/custom-app

Set up rotation schedules for application-specific logs appropriate to your server's usage patterns.

Install AIDE (Advanced Intrusion Detection Environment) for file integrity monitoring. AIDE creates a baseline of system files and can detect unauthorised modifications:

sudo apt install aide
sudo aideinit
sudo mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db

Run integrity checks periodically:

sudo aide --check

Install logwatch to receive daily summaries of system activity:

sudo apt install logwatch

Configure logwatch to send daily reports to a monitored email address. Review these reports each morning to catch unusual activity before it escalates.

Final Checklist Before Moving to Production

Before putting the server into production use, verify each hardening step was completed correctly:

  • SSH daemon: Root login disabled, password authentication disabled, key-based login confirmed working.
  • Firewall: UFW enabled with only necessary ports open, SSH access verified.
  • Updates: Automatic security updates configured and enabled.
  • Services: Unnecessary services stopped and disabled.
  • Fail2ban: Running and actively monitoring SSH logs.
  • Kernel parameters: Network hardening settings applied via sysctl.
  • File protection: Critical binaries marked immutable where appropriate.
  • Monitoring: Logwatch configured for daily reports, AIDE baseline created.

Document every hardening step in a runbook that can be repeated for future server builds. Consistency matters. A repeatable hardening process prevents steps from being missed when provisioning new servers.

Servers running web applications should also review the Apache security configuration guide for web server-specific hardening beyond the initial server setup.