Spun up a fresh Ubuntu 24.04 VPS? Before you install Nginx, deploy your app, or open any service to the internet, there are a few things every new server needs. This guide walks you through the eight essential first steps — creating a secure sudo user, locking down SSH, enabling the firewall, turning on automatic security updates, and more. Do all eight and your server will be hardened, up to date, and ready for production work.
This guide assumes a fresh Ubuntu 24.04 install (works on 22.04 too) with root access, which is how most VPS providers deliver a new server.
Prerequisites
- A fresh Ubuntu 24.04 (or 22.04) VPS or dedicated server
- Root access over SSH (or your provider's console)
- About 20 minutes of focused time
Step 1 — Update and upgrade the system packages
A fresh server image is often weeks or months behind on patches. Update the package index and install every available upgrade before you touch anything else.
apt update && apt upgrade -y
apt update refreshes the list of available packages, and apt upgrade -y installs all updates without prompting. On a fresh image this can take several minutes — let it finish.
While you are at it, install the basic build tools. Some packages you install later (like Node modules or Python packages) need a compiler toolchain:
apt install -y build-essential curl wget git ufw
build-essential bundles gcc, make, and friends; curl, wget, and git are everyday admin tools. The ufw package is Ubuntu's friendly firewall frontend — you will need it in Step 4.
Step 2 — Create a non-root user with sudo access
Working as root all the time is risky: one mistyped command can destroy the system, and root is the first account attackers try to brute-force. Create your own admin user instead.
adduser deploy
This prompts you for a password and some optional profile details. Replace deploy with whatever username you prefer.
Now give the new user sudo privileges:
usermod -aG sudo deploy
-aG appends (-a) the user to the sudo group (-G). Switch to the new account and confirm sudo works:
su - deploy
sudo whoami
sudo whoami should print root, proving the user can elevate privileges when asked.
Step 3 — Set up SSH key authentication for the new user
Password logins are the weakest link in server security. Switch to SSH keys, which are far harder to brute-force.
On your local machine (not the server), generate a key pair if you do not have one yet:
ssh-keygen -t ed25519 -C "your-email@example.com"
Accept the defaults. This creates ~/.ssh/id_ed25519 (private key — never share it) and ~/.ssh/id_ed25519.pub (public key — safe to copy around).
Copy the public key to your new server user:
ssh-copy-id deploy@YOUR_SERVER_IP
Confirm you can log in as deploy without a password prompt before continuing:
ssh deploy@YOUR_SERVER_IP
Do not proceed to Step 4 until key-based login works — you are about to lock down SSH, and locking yourself out is the classic rookie mistake.
Step 4 — Harden SSH
Open the SSH daemon configuration:
sudo nano /etc/ssh/sshd_config
Set (or add) these lines. In sshd_config, the first value wins, so add them at the top of the file or comment out any duplicates below:
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
PermitRootLogin no stops anyone from logging in as root at all — there is no legitimate reason to SSH in as root once you have a sudo user. PasswordAuthentication no disables password logins entirely, forcing key-based auth and defeating most brute-force bots.
Optionally, change the default SSH port to reduce log noise from automated scanners:
Port 2222
This is not real security — attackers port-scan — but it keeps your logs far cleaner. If you change the port, remember it in every future ssh command with -p 2222.
Check the config for syntax errors, then restart SSH:
sudo sshd -t
sudo systemctl restart ssh
sshd -t validates the config without applying it — if it prints nothing, the config is valid. Now, in a new terminal window, open a second SSH session to confirm you can still get in before you close your existing one.
Step 5 — Configure the firewall with UFW
Ubuntu's Uncomplicated Firewall (UFW) makes iptables rules manageable. Start with a deny-everything posture:
sudo ufw default deny incoming
sudo ufw default allow outgoing
Next, allow SSH so you don't lock yourself out (use 2222/tcp instead if you changed the port in Step 4):
sudo ufw allow OpenSSH
Then enable the firewall:
sudo ufw enable
Type y when prompted. Verify the ruleset:
sudo ufw status verbose
You should see SSH allowed and everything else denied. Later, when you install a web server, open HTTP/HTTPS with sudo ufw allow 'Nginx Full' or ports 80/443 as needed.
Step 6 — Enable automatic security updates
Manually patching servers is easy to forget. Let Ubuntu install security updates itself:
sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
Answer Yes at the prompt. Then open the config and make sure security updates are enabled:
sudo nano /etc/apt/apt.conf.d/50unattended-upgrades
Confirm the "${distro_id}:${distro_codename}-security" line is uncommented. You can also add automatic reboots for kernel updates:
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "02:00";
This reboots the server at 2 AM if a kernel update requires it — fine for most VPS workloads. Finally, verify the automation is scheduled:
sudo unattended-upgrade --dry-run
A dry run simulates an update cycle and confirms the configuration is valid without changing anything.
Step 7 — Set the hostname and timezone
Pick a sensible fully-qualified hostname — it shows up in prompts, logs, and mail headers:
sudo hostnamectl set-hostname server1.yourdomain.com
Also add it to /etc/hosts so the name resolves locally:
sudo nano /etc/hosts
Make sure a line maps your server's main IP to the new hostname.
Set the correct timezone so logs and cron jobs fire at sensible times:
sudo timedatectl set-timezone Asia/Kolkata
Use timedatectl list-timezones | grep -i kolkata to find your zone if it differs. Confirm with:
timedatectl
Step 8 — Add a swap file and install fail2ban
Small VPS instances run out of RAM fast. A swap file gives the system breathing room during memory spikes:
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
This creates a 2 GB swap file (scale it to your RAM: 2 GB is fine for 1–4 GB VPS), locks permissions down to root, formats and activates it, then adds it to fstab so it survives reboots. Confirm with free -h.
Finally, install fail2ban to block brute-force attempts automatically:
sudo apt install -y fail2ban
sudo systemctl enable --now fail2ban
Fail2ban's default SSH jail works out of the box — after a handful of failed logins from one IP, that IP gets banned. Check the active jails:
sudo fail2ban-client status sshd
Verify it worked
Run these quick checks and you should see the new, hardened state:
sudo ufw status
# SSH (or 2222) ALLOW, everything else denied
sudo systemctl is-active fail2ban
# active
timedatectl
# shows your timezone
free -h
# shows the swap file
ssh root@YOUR_SERVER_IP
# Permission denied — root login disabled, as intended
That last check is the satisfying one: a root login attempt that fails on purpose means your hardening is working.
Common issues & fixes
1. Locked out of SSH after hardening
Symptom: "Permission denied (publickey)" on every login.
Fix: Use your VPS provider's web console (VNC) to log in as root, then review /etc/ssh/sshd_config for a typo or duplicated conflicting lines (remember: first value wins). Restart SSH with systemctl restart ssh and test from a new terminal before closing the console.
2. UFW blocked your access
Symptom: SSH times out after ufw enable.
Fix: Connect via the provider console and run sudo ufw allow OpenSSH (or sudo ufw allow 2222/tcp for a custom port), then sudo ufw reload. Always add the SSH rule before enabling the firewall.
3. swapon: /swapfile: read swap header failed
Symptom: Activating the swap file fails.
Fix: You skipped mkswap — the file must be formatted before activation. Run sudo mkswap /swapfile then sudo swapon /swapfile again.
4. fail2ban banned your own IP
Symptom: You can reach the server but SSH connections from your office/home IP time out.
Fix: From the provider console, unban yourself: sudo fail2ban-client set sshd unbanip YOUR_IP. To avoid repeats, add your static IP to the ignoreip list in /etc/fail2ban/jail.local.
5. Unattended upgrades never seem to run
Symptom: Weeks pass and apt list --upgradable still shows pending security updates.
Fix: Check /etc/apt/apt.conf.d/20auto-upgrades — both lines should be 1. Then run sudo unattended-upgrade --dry-run --debug to see what the updater would do and which step is misconfigured.
Your Ubuntu 24.04 server is now updated, running under a secure non-root user, locked down with key-only SSH, protected by a firewall and fail2ban, patched automatically, and properly named and timed. This is the foundation every production server should sit on — and it is exactly the starting point we use for every client deployment at XpertBees. If you'd rather have us harden and manage your servers, reach out — server setup is what we do every day.



