Things to Do After Installing Ubuntu Server 22.04 to Avoid 2 AM Disasters

Ubuntu tutorial - IT technology blog
Ubuntu tutorial - IT technology blog

Fresh Server, Trouble Before You Even Start

When I first switched from CentOS to Ubuntu, my habit was to deploy code immediately after installation — skipping every configuration step. Three days later, the server got brute-forced via SSH, logs were flooded with error messages, and the lack of a swap file caused a Node.js process to get killed by the OOM killer at 2 AM.

It took about a week to get used to Ubuntu’s package management after leaving CentOS. But the more painful part was losing an entire morning restoring services from backup — for mistakes that were completely avoidable with 20 minutes of upfront configuration.

This post is the checklist I run through every time I install Ubuntu Server 22.04. Nothing fancy — just lessons I’ve paid for with real production incidents.

Why Are Freshly Installed Servers Prone to Trouble?

A fresh Ubuntu Server 22.04 install looks fine on the surface, but there are a few genuinely dangerous defaults if left unchanged:

  • SSH allows password login: Bot scanners constantly sweep the entire internet. A newly public IP is typically probed within minutes — trying thousands of username/password combinations like root/123456, admin/admin, ubuntu/ubuntu.
  • UFW is installed but not enabled: All ports are reachable from the outside. By default.
  • Packages may be months out of date: The ISO was built at release time and may contain vulnerabilities that have long since been patched.
  • No swap: Cloud VPS instances typically skip the swap partition. When RAM fills up, the OOM killer steps in without warning.
  • Default timezone is UTC: Logs show 03:00 when it’s actually 10 AM local time — a debugging nightmare.

Steps to Take — In Order of Priority

1. Update the System Immediately

Before anything else. Deploying before updating is an unnecessary risk:

sudo apt update && sudo apt upgrade -y
sudo apt autoremove -y

If the kernel was updated, reboot immediately:

sudo reboot

2. Create a Dedicated User — Don’t Use Root

Logging in directly as root is bad practice — one wrong command can break the entire system with nothing to stop it. Create a new user with sudo privileges:

adduser deploy
usermod -aG sudo deploy

Log in with the new user to test permissions before locking out root.

3. Set Up SSH Keys and Disable Password Login

Brute-force bots try passwords — disabling password login eliminates that attack vector entirely. On your local machine:

# Create an SSH key if you don't have one
ssh-keygen -t ed25519 -C "[email protected]"

# Copy the public key to the server
ssh-copy-id deploy@your-server-ip

Once you’ve successfully logged in with the key, edit /etc/ssh/sshd_config:

sudo nano /etc/ssh/sshd_config

Edit these three lines:

PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes

Restart SSH:

sudo systemctl restart sshd

Important: Keep your existing SSH session open while testing the new one. If you get locked out, the old session is still there to fix things.

4. Enable UFW Firewall

Only open ports you actually need, close everything else:

# Allow SSH first — required, or you'll lock yourself out
sudo ufw allow ssh

# If running a web server
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

# Enable firewall
sudo ufw enable

# Check result
sudo ufw status verbose

Running SSH on a custom port, like 2222? Add this line before enabling:

sudo ufw allow 2222/tcp

5. Configure the Timezone

If your server is deployed for Vietnamese users, set the timezone accordingly — it makes reading logs much less confusing:

sudo timedatectl set-timezone Asia/Ho_Chi_Minh

# For a server in Japan, use this instead
sudo timedatectl set-timezone Asia/Tokyo

# Check
timedatectl status

6. Create a Swap File

That 2 AM OOM incident I mentioned at the top? The root cause was no swap. Any Node.js process that used a bit too much RAM got killed immediately — no buffer. For a cloud VPS with 1-2GB RAM, a 2GB swap file is a reasonable starting point:

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

# Check
free -h

# Auto-mount on reboot
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

Linux starts using swap fairly early by default (swappiness=60). Production servers should set this to 10 — only use swap when truly necessary:

echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

7. Install Essential Packages

These tools aren’t always needed right away, but when you need to debug and they’re missing, it’s genuinely frustrating:

sudo apt install -y \
  curl wget git vim htop \
  net-tools dnsutils \
  unzip build-essential \
  fail2ban

8. Configure Fail2ban

Even with password login disabled, bots keep hammering the connection and spamming your logs. Fail2ban automatically blocks IPs after N failed attempts:

sudo systemctl enable fail2ban
sudo systemctl start fail2ban

# Check status — how many IPs have been blocked
sudo fail2ban-client status sshd

9. Enable Automatic Security Updates

Nobody remembers to manually update the server every week. Let it handle itself:

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

Choose “Yes” when prompted. Only security patches are applied automatically — not all packages — so there’s no risk of an update breaking your application.

10. Check What Services Are Running

Final step: review whether anything unnecessary is exposed to the outside:

# Which ports are listening?
sudo ss -tlnp

# Which services are running?
sudo systemctl list-units --type=service --state=running

Disable anything you don’t need:

sudo systemctl disable --now snapd      # Disable if you don't use snap
sudo systemctl disable --now bluetooth  # Servers don't need Bluetooth

Bundle It All Into a Script for Next Time

After going through this 4-5 times, I wrote a script. One command covers the first 6 steps — no need to remember each one:

#!/bin/bash
# bootstrap-ubuntu.sh — Run immediately after installing Ubuntu Server 22.04
set -e

echo "[1/6] Updating system..."
apt update && apt upgrade -y && apt autoremove -y

echo "[2/6] Installing essential packages..."
apt install -y curl wget git vim htop net-tools dnsutils unzip fail2ban

echo "[3/6] Setting up swap..."
if [ ! -f /swapfile ]; then
  fallocate -l 2G /swapfile
  chmod 600 /swapfile
  mkswap /swapfile
  swapon /swapfile
  echo '/swapfile none swap sw 0 0' >> /etc/fstab
  echo 'vm.swappiness=10' >> /etc/sysctl.conf
fi

echo "[4/6] Configuring UFW..."
ufw allow ssh
ufw --force enable

echo "[5/6] Enabling Fail2ban..."
systemctl enable fail2ban
systemctl start fail2ban

echo "[6/6] Enabling auto security updates..."
apt install -y unattended-upgrades
dpkg-reconfigure --priority=low unattended-upgrades

echo "Done! Don't forget to:"
echo "  - Create a non-root user"
echo "  - Set up SSH key auth and disable password login"
echo "  - Set correct timezone: timedatectl set-timezone Asia/Ho_Chi_Minh"

Run as root:

chmod +x bootstrap-ubuntu.sh
sudo ./bootstrap-ubuntu.sh

Quick Checklist Before Deploying

Once everything is done, run these quick commands to make sure nothing was missed:

# Is UFW enabled?
sudo ufw status

# Is SSH password login disabled?
grep -E 'PermitRootLogin|PasswordAuthentication' /etc/ssh/sshd_config

# Is swap active?
free -h

# Is the timezone correct?
date

# Is Fail2ban running?
sudo fail2ban-client status

The whole thing takes about 15-20 minutes. The first time might take longer as you read through each step’s output — the second time, just run the script and you’re done. Restoring from backup after an incident cost me nearly 4 hours, not counting the half day of debugging afterward to make sure nothing else was broken.

Share: