← All articles
LINUX Ubuntu Server Initial Setup: Security Hardening for ... 2026-02-09 · ubuntu · linux · security

Ubuntu Server Initial Setup: Security Hardening for Home Labs

Linux 2026-02-09 ubuntu linux security ssh firewall hardening homelab

You've installed Ubuntu Server, it booted successfully, and you can log in. Now what? A default Ubuntu Server installation is functional but not particularly secure. It accepts password-based SSH logins from anywhere, has no firewall rules, and doesn't automatically install security updates. For a home lab server that's going to run 24/7 on your network, spending 30 minutes on basic hardening makes a real difference.

This guide walks through the essential post-installation security steps for Ubuntu Server 24.04 LTS. Everything here applies equally well to 22.04 or Debian 12 with minor differences.

Step 1: Update Everything

Before doing anything else, make sure the system is fully up to date.

sudo apt update && sudo apt upgrade -y

# If a kernel was updated, reboot
sudo reboot

This pulls in any security patches released since the ISO was built. On a fresh install, there are usually several.

Step 2: Create a Non-Root User (If Needed)

If you only created root during installation (common with minimal installs), create a regular user immediately. Running everything as root is a bad habit that will bite you eventually.

# Create a user and add to sudo group
adduser yourname
usermod -aG sudo yourname

# Test it works
su - yourname
sudo whoami  # Should print "root"

The Ubuntu Server installer usually creates a regular user for you, so this step may already be done. Either way, never SSH in as root — always use your regular user and sudo when needed.

Step 3: Set Up SSH Key Authentication

Password authentication over SSH is the single biggest attack vector for internet-facing servers. Bots constantly scan for SSH servers and try common username/password combinations. SSH keys eliminate this risk entirely.

Generate a Key Pair (On Your Local Machine)

# On your laptop/desktop — NOT on the server
ssh-keygen -t ed25519 -C "yourname@your-laptop"

# When prompted for a file, press Enter for the default (~/.ssh/id_ed25519)
# When prompted for a passphrase, use a strong one (or leave blank for convenience)

Ed25519 is the modern standard — it's faster and more secure than RSA with much shorter keys. If you need RSA compatibility for older systems, use ssh-keygen -t rsa -b 4096.

Copy the Key to Your Server

# From your local machine
ssh-copy-id yourname@192.168.1.100

# Or manually if ssh-copy-id isn't available:
cat ~/.ssh/id_ed25519.pub | ssh yourname@192.168.1.100 "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"

Test that key-based login works before proceeding:

ssh yourname@192.168.1.100
# Should log in without asking for a password

Disable Password Authentication

Once key-based login is confirmed working, disable password authentication entirely:

sudo nano /etc/ssh/sshd_config

Find and change these lines (or add them if they don't exist):

PasswordAuthentication no
PubkeyAuthentication yes
PermitRootLogin no
PermitEmptyPasswords no
MaxAuthTries 3

Important settings explained:

Apply the changes:

sudo systemctl restart sshd

Before closing your current SSH session, open a new terminal and verify you can still log in. If key auth is misconfigured and you've disabled passwords, you'll be locked out. Always test with a second connection first.

Optional: Change the SSH Port

Changing SSH from port 22 to something else (like 2222) eliminates 99% of automated scanning noise. It's security through obscurity — it doesn't protect against a determined attacker, but it reduces log spam dramatically.

# In /etc/ssh/sshd_config
Port 2222

# Restart SSH
sudo systemctl restart sshd

# Connect with the new port
ssh -p 2222 yourname@192.168.1.100

If you change the port, remember to update your firewall rules (next section) and your SSH config on your local machine:

# ~/.ssh/config (on your local machine)
Host homelab
    HostName 192.168.1.100
    User yourname
    Port 2222

Step 4: Configure the Firewall (UFW)

Ubuntu includes UFW (Uncomplicated Firewall), a friendly wrapper around iptables/nftables. By default, it's installed but not enabled.

# Allow SSH (do this BEFORE enabling the firewall!)
sudo ufw allow ssh
# Or if you changed the port:
sudo ufw allow 2222/tcp

# Enable the firewall
sudo ufw enable

# Check status
sudo ufw status verbose

Now add rules for the services you'll actually run:

# Allow HTTP and HTTPS (for web services)
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

# Allow specific services by port
sudo ufw allow 8080/tcp    # Portainer, etc.
sudo ufw allow 53          # DNS (Pi-hole) — both TCP and UDP

# Allow from a specific subnet only (more restrictive)
sudo ufw allow from 192.168.1.0/24 to any port 9090  # Prometheus from LAN only

# Deny everything else (default policy)
sudo ufw default deny incoming
sudo ufw default allow outgoing

# View all rules
sudo ufw status numbered

# Delete a rule by number
sudo ufw delete 3

The principle: deny everything by default, then explicitly allow only the ports you need. For a home lab server, this typically means SSH, HTTP/HTTPS, and whatever specific ports your services use.

Step 5: Install and Configure Fail2ban

Fail2ban monitors log files for repeated failed authentication attempts and temporarily bans the offending IP addresses. Even with SSH key authentication, it's worth running — it catches brute-force attempts against any service with authentication.

sudo apt install fail2ban -y

Create a local configuration file (don't edit the default jail.conf — it gets overwritten on updates):

sudo nano /etc/fail2ban/jail.local
[DEFAULT]
# Ban for 1 hour after 3 failures within 10 minutes
bantime = 3600
findtime = 600
maxretry = 3
# Use nftables as the backend (modern Ubuntu)
banaction = nftables-multiport

[sshd]
enabled = true
port = ssh
# If you changed the SSH port:
# port = 2222

# Optional: protect other services
[nginx-http-auth]
enabled = true

[apache-auth]
enabled = true

Start and enable fail2ban:

sudo systemctl enable --now fail2ban

# Check status
sudo fail2ban-client status
sudo fail2ban-client status sshd

# View banned IPs
sudo fail2ban-client status sshd

# Manually unban an IP
sudo fail2ban-client set sshd unbanip 192.168.1.50

Step 6: Enable Unattended Upgrades

Security vulnerabilities in installed packages are discovered regularly. Unattended upgrades automatically install security patches without manual intervention. For a home lab server, this is the right trade-off — the small risk of a breaking update is far outweighed by the risk of an unpatched vulnerability.

sudo apt install unattended-upgrades -y
sudo dpkg-reconfigure -plow unattended-upgrades
# Select "Yes" when prompted

Verify the configuration:

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

The important lines:

// Security updates — should already be enabled
Unattended-Upgrade::Allowed-Origins {
    "${distro_id}:${distro_codename}-security";
    "${distro_id}ESMApps:${distro_codename}-apps-security";
};

// Auto-reboot if needed (optional — enable for truly hands-off operation)
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "04:00";

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

The auto-reboot setting is a personal choice. If your services can handle a brief reboot at 4 AM, enable it. If you run critical services that can't tolerate downtime, leave it off and reboot manually when you see the /var/run/reboot-required file.

# Check if a reboot is pending
cat /var/run/reboot-required 2>/dev/null || echo "No reboot required"

# Test unattended upgrades
sudo unattended-upgrades --dry-run --debug

Step 7: Harden System Settings

A few sysctl tweaks improve security without affecting normal operation:

sudo nano /etc/sysctl.d/99-hardening.conf
# Prevent IP spoofing
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1

# Ignore ICMP redirects (prevents MITM attacks)
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0

# Don't send ICMP redirects (we're not a router... usually)
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0

# Ignore broadcast pings
net.ipv4.icmp_echo_ignore_broadcasts = 1

# Log suspicious packets
net.ipv4.conf.all.log_martians = 1

# Disable IPv6 if you don't use it (reduces attack surface)
# net.ipv6.conf.all.disable_ipv6 = 1
# net.ipv6.conf.default.disable_ipv6 = 1

Apply the settings:

sudo sysctl --system

Step 8: Set Up Basic Monitoring

You want to know when something goes wrong without having to log in and check manually.

# Install useful monitoring tools
sudo apt install -y htop iotop ncdu tmux

# htop — interactive process viewer (better than top)
htop

# iotop — see which processes are doing disk I/O
sudo iotop

# ncdu — find what's eating disk space
ncdu /

# Check disk space
df -h

# Check memory usage
free -h

# Check for listening ports
sudo ss -tlnp

For persistent monitoring, set up simple alerting. The cheapest option is a systemd timer that checks disk space and sends a warning:

# Create a simple disk space check script
sudo nano /usr/local/bin/check-disk.sh
#!/bin/bash
THRESHOLD=85
USAGE=$(df / | tail -1 | awk '{print $5}' | tr -d '%')

if [ "$USAGE" -gt "$THRESHOLD" ]; then
    echo "WARNING: Disk usage is ${USAGE}% on $(hostname)" | \
        mail -s "Disk Alert: $(hostname)" your-email@example.com
fi
sudo chmod +x /usr/local/bin/check-disk.sh

Step 9: Disable Unnecessary Services

A minimal Ubuntu Server installation doesn't have much running, but check anyway:

# List enabled services
systemctl list-unit-files --state=enabled

# List listening network services
sudo ss -tlnp

# Disable anything you don't need. Common candidates:
sudo systemctl disable --now snapd       # If you don't use snaps
sudo systemctl disable --now multipathd  # Unless you have SAN storage

The fewer services running, the smaller the attack surface and the lower the resource usage.

Security Checklist

After completing this guide, verify your setup:

# 1. SSH key auth works
ssh yourname@192.168.1.100

# 2. Password auth is disabled
ssh -o PubkeyAuthentication=no yourname@192.168.1.100
# Should fail with "Permission denied (publickey)"

# 3. Root login is blocked
ssh root@192.168.1.100
# Should fail

# 4. Firewall is active
sudo ufw status

# 5. Fail2ban is running
sudo fail2ban-client status

# 6. Unattended upgrades are configured
sudo unattended-upgrades --dry-run

# 7. System is up to date
sudo apt update && apt list --upgradable

These steps take about 30 minutes on a fresh install and dramatically improve your security posture. None of this makes your server impenetrable — nothing does — but it closes the most common attack vectors and gives you a solid foundation. As your home lab grows, you can add more layers: VPN access, centralized logging, IDS/IPS systems, and network segmentation. But this baseline will serve you well for a long time.