Linux·7 min read·

Minimal Ubuntu Server 24.04 Setup for Production

A lean Ubuntu Server 24.04 baseline for real workloads: unattended security updates, UFW, SSH hardening, and key-only logins in about twenty minutes.

NB

Netbay Engineering

Netbay Engineering

On this page

An Ubuntu 24.04 LTS cloud image boots clean, current, and already configured to accept your SSH key through cloud-init. That is a good starting point, but it is not yet a production baseline: convenience packages you do not need are installed, password authentication is still enabled, no host firewall is running, and automatic security updates are not switched on by default. The distance between a bootable image and a lean, patched, locked-down base is about twenty minutes of deliberate work. This walkthrough covers exactly that path, sized for a VPS you intend to run for months and happy to clone across a fleet.

Lean Ubuntu 24.04 production baseline 1. BOOT minimal image update + purge 2. ADMIN deploy user sudo + key 3. SSH key only root login off 4. UFW deny default 80, 443, ssh 5. AUTO-UPD unattended security suite 6. VERIFY sshd -t status checks A box that skips a step ships without that protection

Start From the Minimal Image

Ubuntu's minimal install option skips the desktop and a shelf of convenience applications, and the difference shows up in maintenance rather than disk: fewer packages to patch, fewer background services to reason about during an incident, and a security audit you can finish in an afternoon. Cloud images are already fairly lean, but the same instinct applies, so verify what actually booted before changing anything.

bash
cat /etc/os-release | head -2
uname -r
free -m | head -2
df -h /

On a minimal server there is one package worth removing by hand, because it ships with the default base whether you asked for it or not: snapd, the runtime behind Ubuntu's software-store apps. A headless production box rarely uses it, and it launches background services and mounts squashfs units that a deliberately small system should not carry.

bash
sudo systemctl disable --now snapd
sudo apt-get purge -y snapd
sudo rm -rf /var/cache/snapd /var/lib/snapd

Create an Admin User, Not Root

Daily work should never run as root, and sudo gives you an audit trail for every privileged command. Create an unprivileged user, give it passwordless sudo so provisioning scripts do not stall on prompts, and park its SSH key in place before you change anything about the SSH daemon.

bash
sudo adduser --disabled-password deploy
echo 'deploy ALL=(ALL) NOPASSWD:ALL' | sudo tee /etc/sudoers.d/deploy
sudo install -d -o deploy -g deploy -m 700 /home/deploy/.ssh
echo 'ssh-ed25519 <your-public-key>' | sudo tee /home/deploy/.ssh/authorized_keys
sudo chmod 600 /home/deploy/.ssh/authorized_keys
sudo chown -R deploy:deploy /home/deploy

Test the new login in a second terminal before locking anything down. With the key proven, disable root login and password authentication via a drop-in file, which overrides the defaults without editing the main configuration.

bash
sudo tee /etc/ssh/sshd_config.d/99-hardening.conf >/dev/null <<'EOF'
PermitRootLogin no
PasswordAuthentication no
MaxAuthTries 3
EOF
sudo sshd -t && sudo systemctl reload sshd

The sshd -t call validates the syntax before the reload, so a typo cannot lock you out. Keep the original session open until you have logged in as deploy from a fresh connection.

UFW for the Inbound Surface

AppArmor protects individual processes; the host firewall protects the network edge, and a fresh Ubuntu box has none to begin with. ufw is the simplest way to state the policy: deny everything inbound except the few ports the server actually answers on.

bash
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose

Set the default to deny, then allow SSH plus the web ports explicitly. Every allow line is a deliberate decision; leaving everything else out is the entire point. If you moved SSH to a custom port, allow that port instead of the OpenSSH profile.

Unattended Security Updates

The update prompt disappears on a server, so patching has to be automatic. Ubuntu ships unattended-upgrades in the base install, but it is not enabled by default. Flip on periodic updates and unattended upgrades, and leave the rest of the box on scheduled attention.

ini
// /etc/apt/apt.conf.d/20auto-upgrades
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
APT::Periodic::AutocleanInterval "7";
bash
sudo dpkg-reconfigure --priority=low unattended-upgrades
sudo systemctl status unattended-upgrades

What you want at the end is the security portion of the patch stream installing itself within a day of publication, with the kernel and anything else that demands a reboot left for your scheduled maintenance window. Ubuntu 24.04 records reboot eligibility in /var/run/reboot-required, so the patch loop never surprises you with unscheduled restarts.

Takeaway

Four moves turn a cloud image into a production base: trim it, create a key-based admin user, refuse root and password SSH, and let the security patches apply themselves. None of it is exotic and all of it fits inside the first hour of a new deployment. Repeating the same twenty-minute baseline on every box in the fleet is what makes the fleet's failure modes predictable.

Spin up an Ubuntu 24.04 LTS VPS on Netbay in under 60 seconds and run this baseline before any traffic points at it — netbayhosts.in.

Keep reading

Follow along on a real VPS

Deploy Linux in under 60 seconds

These guides are written against Ubuntu, Debian, and RHEL-family images — the same ones on NetBay.

Deploy an instance