DevOpsil
Linux
91%
Needs Review

Ubuntu 24.04 LTS Server Setup for Production: From Bare Metal to Hardened Baseline

Raafay AsifRaafay Asif5 min read

You Rebooted Into a Fresh Ubuntu 24.04 Server. Now What?

Most tutorials stop at "it booted." Production means something different: minimal attack surface, a non-root user with sudo, SSH locked to keys, a firewall that defaults to deny, and sensible kernel parameters before you put anything on it.

This is the checklist I run on every Ubuntu 24.04 LTS server before deploying workloads. Noble Numbat is the current LTS — supported until April 2029 with ESM extending to 2034.


1. Initial Login and User Setup

You're probably logging in as root initially. First thing: create a non-root user and lock root SSH.

# Create a deploy user (replace with your username)
adduser deploy
usermod -aG sudo deploy

# Switch to the new user and verify sudo works
su - deploy
sudo whoami   # should print: root

Set up SSH key auth for the new user before you do anything else:

# On your local machine — copy your public key
ssh-copy-id deploy@<server-ip>

# Or manually
mkdir -p ~/.ssh
chmod 700 ~/.ssh
echo "ssh-ed25519 AAAA... your-key-comment" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

2. Harden SSH

Edit /etc/ssh/sshd_config:

sudo nano /etc/ssh/sshd_config

Set these explicitly:

Port 2222                          # non-default port reduces noise
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
X11Forwarding no
AllowTcpForwarding no
MaxAuthTries 3
LoginGraceTime 20
ClientAliveInterval 300
ClientAliveCountMax 2

Restart and verify — don't close your current session until you've tested the new config:

sudo systemd-analyze verify sshd   # syntax check
sudo systemctl restart ssh
# Open a NEW terminal and test login before closing current session
ssh -p 2222 deploy@<server-ip>

3. Configure UFW

Ubuntu ships with UFW (Uncomplicated Firewall). Enable it with a default-deny posture:

# Default: deny all in, allow all out
sudo ufw default deny incoming
sudo ufw default allow outgoing

# Allow your SSH port
sudo ufw allow 2222/tcp comment 'SSH'

# Allow HTTP/HTTPS if this is a web server
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

# Enable
sudo ufw enable
sudo ufw status verbose

Rate-limit SSH to slow brute-force attempts (built into UFW):

sudo ufw limit 2222/tcp

4. Automatic Security Updates

Ubuntu 24.04 ships unattended-upgrades. Enable it so security patches apply without manual intervention:

sudo apt install unattended-upgrades apt-listchanges -y
sudo dpkg-reconfigure --priority=low unattended-upgrades

Edit /etc/apt/apt.conf.d/50unattended-upgrades to configure:

Unattended-Upgrade::Allowed-Origins {
    "${distro_id}:${distro_codename}-security";
};
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "03:00";
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
Unattended-Upgrade::Remove-New-Unused-Dependencies "true";

Verify it's working:

sudo unattended-upgrade --dry-run --debug 2>&1 | head -30

5. Kernel Parameters

Edit /etc/sysctl.d/99-production.conf:

# Network hardening
net.ipv4.tcp_syncookies = 1
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1

# Increase connection queue
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 4096

# File descriptors
fs.file-max = 500000

# Disable IPv6 if not needed
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1

Apply immediately:

sudo sysctl --system

6. Swap Configuration

Ubuntu 24.04 cloud images often ship with no swap. Add a 2GB swap file:

sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

# Make permanent
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

# Tune swappiness — prefer RAM, only use swap when necessary
echo 'vm.swappiness=10' | sudo tee /etc/sysctl.d/99-swappiness.conf
sudo sysctl vm.swappiness=10

7. Disable Unnecessary Services

Check what's running:

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

Common candidates to disable on a server:

sudo systemctl disable --now snapd        # if you don't use snaps
sudo systemctl disable --now avahi-daemon  # mDNS discovery — not needed on servers
sudo systemctl disable --now cups          # printing
sudo systemctl disable --now bluetooth     # if no BT hardware

8. Fail2ban

Install and configure fail2ban to block repeated SSH failures:

sudo apt install fail2ban -y

cat > /etc/fail2ban/jail.local << 'EOF'
[DEFAULT]
bantime  = 1h
findtime = 10m
maxretry = 5

[sshd]
enabled = true
port    = 2222
logpath = %(sshd_log)s
backend = %(sshd_backend)s
EOF

sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd

9. Verify the Baseline

Quick audit of your hardened server:

# Check listening ports
ss -tlnp

# Check sudo access
sudo -l

# Review auth log for anomalies
sudo journalctl -u ssh -n 50

# Check for setuid binaries that shouldn't be there
find / -perm -4000 -type f 2>/dev/null | grep -v -E "(passwd|sudo|ping|mount|su)"

# Review crontabs
sudo crontab -l 2>/dev/null
crontab -l 2>/dev/null
ls /etc/cron.d/ /etc/cron.daily/ /etc/cron.weekly/

The Baseline Checklist

ItemCommand
Non-root sudo useradduser deploy && usermod -aG sudo deploy
SSH keys onlyPasswordAuthentication no in sshd_config
Non-default SSH portPort 2222
Firewall enabledufw enable
Auto security updatesdpkg-reconfigure unattended-upgrades
Swap configured/swapfile + vm.swappiness=10
Fail2ban runningsystemctl status fail2ban
Unnecessary services offsystemctl disable snapd avahi-daemon

This is your day-zero baseline. From here you install your actual workload — Docker, a web server, a database, or whatever this machine is for. But this foundation doesn't change regardless of workload.

Share:

Was this article helpful?

Raafay Asif
Raafay Asif

Linux Systems Engineer

Everything runs on Linux — I make sure it runs well. From kernel tuning to systemd debugging, I live in the terminal. If your server is misbehaving, I've probably seen that exact dmesg output before.

Related Articles

More in Linux

View all →

Discussion