BASIC
Tested for real: I ran every command in this guide top-to-bottom on a fresh Ubuntu 24.04 virtual machine (4 CPUs, 8 GB RAM) on 13 August 2026. Versions at test time: Ubuntu 24.04.4 LTS, UFW 0.36.2, unattended-upgrades 2.9.1.
Found a problem? Tell me via the contact page.
Placeholders: anything in CAPS-WITH-DASHES, like
YOUR-SERVER-IP, is a placeholder for your own value. Replace it before running the command.
What you'll end up with
- A fully updated server.
- A personal account with admin rights, instead of living as an all-powerful user.
- A firewall that blocks everything except SSH, and security updates that install themselves.
That is the honest minimum I do to any machine before it is allowed to run anything.
The finished state:
Status: active
Default: deny (incoming), allow (outgoing), disabled (routed)
To Action From
-- ------ ----
22/tcp (OpenSSH) ALLOW IN Anywhere
22/tcp (OpenSSH (v6)) ALLOW IN Anywhere (v6)
Who this is for
BASIC. You have just been handed a fresh Ubuntu server — rented or home-made — and can log into it. One path, no branching, all jargon defined.
Time and cost
Measured on the test machine: updates took 65 seconds; every other command ran in under 5. My full run took 12 minutes. Allow 30 minutes at a careful, read-everything pace. Cost: nothing.
Words you'll meet
- SSH — Secure Shell, the remote command line you are using to reach the server. See the back-to-basics page.
- sudo — "do this one command as the administrator". Safer than being the administrator all day.
- root — the all-powerful account. We aim to never log in as it.
- Firewall — a doorkeeper that decides which network connections may reach the machine. Ours is UFW, the Uncomplicated Firewall.
- Package — Ubuntu's unit of installable software, handled by the
aptcommand. - Timer — systemd's version of a scheduled task; Ubuntu uses timers to run updates on its own.
Before you start
- A fresh Ubuntu server (I tested 24.04) and a working login. If your provider gave you
root, log in as that for now — fixing it is Step 2. - Its address. Replace
YOUR-SERVER-IPbelow with it. Placeholders are always CAPS-WITH-DASHES here. - Ten quiet minutes. One step can lock you out if you rush (Step 3 — I show you exactly how).
- Optional but wise: know where your provider's web console is. It is the spare key if SSH is ever blocked.
The steps
Step 1 — update everything first
A fresh server image is weeks or months old, so known, already-fixed holes are still open on it. Updating first closes them before we do anything else.
sudo apt update
Your output will vary, but look for:
Hit:1 http://archive.ubuntu.com/ubuntu noble InRelease
[...snipped...]
26 packages can be upgraded. Run 'apt list --upgradable' to see them.
Your number will differ — that is fine. Now install the updates. This is the slow step; mine took 58 seconds:
sudo apt upgrade -y
You should see something like:
[...snipped...]
Restarting services...
systemctl restart multipathd.service packagekit.service polkit.service qemu-guest-agent.service rsyslog.service ssh.service udisks2.service
[...snipped...]
Check it worked: run sudo apt upgrade -y again — it should say 0 upgraded. If the earlier output mentioned *** System restart required *** or listed a new kernel, reboot when convenient with sudo reboot. My test machine received a new kernel and needed one.
Step 2 — make a personal account with admin rights
Living as root (or as the provider's shared default account) means every typo runs with full power. Every login is a login to everything. A personal account plus sudo gives the same abilities with a seatbelt.
Replace YOUR-NEW-USERNAME with a name you like — I used sam in testing:
sudo adduser YOUR-NEW-USERNAME
You should see something like:
info: Adding user `sam' ...
info: Adding new group `sam' (1001) ...
info: Adding new user `sam' (1001) with group `sam (1001)' ...
info: Creating home directory `/home/sam' ...
info: Copying files from `/etc/skel' ...
New password:
Retype new password:
passwd: password updated successfully
Changing the user information for sam
Enter the new value, or press ENTER for the default
Full Name []:
[...snipped...]
Is the information correct? [Y/n] Y
Type a strong password twice, press Enter through the name-and-phone questions (they are optional), and confirm with Y.
Now grant the account sudo rights:
sudo usermod -aG sudo YOUR-NEW-USERNAME
Check it worked:
groups YOUR-NEW-USERNAME
The important line is:
sam : sam sudo users
The word sudo in that list is the part that matters.
Step 3 — firewall: allow SSH BEFORE switching it on
This is the step that locks people out, so let me show you the trap before we walk around it. UFW's default is: deny everything incoming. If you enable it before allowing SSH, every new SSH connection is blocked — including yours.
I did this to my test machine on purpose. From a second terminal, a fresh connection just hangs and then:
ssh: connect to host YOUR-SERVER-IP port 22: Connection timed out
Note it is a silent timeout, not a "refused" — the firewall drops the packets without answering. The only reasons I could recover: my existing session survived (firewalls let established connections continue), and I had a console as backup. So: do not close your current terminal during this step, and run the commands in this exact order.
Allow SSH first. UFW ships a named profile for it, so no port numbers needed:
sudo ufw allow OpenSSH
A passing run includes:
Rules updated
Rules updated (v6)
Only now do we switch the firewall on:
sudo ufw enable
You should see something like:
Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
Firewall is active and enabled on system startup
That warning is exactly the trap we just walked around; answer y — your rule is already in place.
Check it worked:
sudo ufw status verbose
Your output will vary, but look for:
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip
To Action From
-- ------ ----
22/tcp (OpenSSH) ALLOW IN Anywhere
22/tcp (OpenSSH (v6)) ALLOW IN Anywhere (v6)
The load-bearing lines: Status: active, Default: deny (incoming), and the OpenSSH ALLOW rule. Then open a second terminal and confirm a fresh ssh login still works before closing anything.
One honest caveat for later: if you ever run Docker on this machine, published container ports bypass UFW. That deserves its own guide; for today's SSH-only setup, UFW's promise holds.
Step 4 — check automatic security updates are really on
Ubuntu 24.04 ships with unattended-upgrades installed and switched on. I do not trust "should be on"; we check. Two scheduled timers do the work — one refreshes package lists, one installs security updates:
systemctl list-timers 'apt-daily*'
A passing run includes:
NEXT LEFT LAST PASSED UNIT ACTIVATES
Thu 2026-08-13 21:42:46 UTC 5h 26min Thu 2026-08-13 15:42:24 UTC - apt-daily.timer apt-daily.service
Fri 2026-08-14 06:37:49 UTC 14h Thu 2026-08-13 15:42:24 UTC - apt-daily-upgrade.timer apt-daily-upgrade.service
2 timers listed.
Both timers present with a NEXT time is the pass mark. Now confirm the switch that connects the timers to actual upgrading is set:
cat /etc/apt/apt.conf.d/20auto-upgrades
You should see something like:
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
Both lines ending "1" means on. Finally, a rehearsal — ask it what it would do, without doing it:
sudo unattended-upgrade --dry-run --debug 2>&1 | tail -5
The important line is:
Fetched 0 B in 0s (0 B/s)
fetch.run() result: 0
Packages blacklist due to conffile prompts: []
No packages found that can be upgraded unattended and no pending auto-removals
The list of kept packages can't be calculated in dry-run mode.
"No packages found" is correct — Step 1 already installed everything, so there is nothing left for it to do. The point is that it ran without error.
Check it worked: timers listed, both "1" lines present, dry-run completed.
Step 5 — confirm your new account works end to end
Before you log out, prove the new account can get in and administrate. From your laptop, in a new terminal:
ssh YOUR-NEW-USERNAME@YOUR-SERVER-IP
Then, once in:
sudo whoami
A passing run includes:
[sudo] password for sam:
root
Check it worked: the answer is root. That single word means the new account can do everything the old one could. From now on, use this account.
Something went wrong?
- You see
Connection timed outon a new SSH connection after Step 3 → it means UFW went on before the OpenSSH rule (order matters) → in any terminal that is still logged in, runsudo ufw allow OpenSSH; with no surviving session, use your provider's web console and run the same command there. - You see
systemctl is-enabled unattended-upgradesreportdisabled→ it means you checked the wrong unit; that one only finishes upgrades during shutdown → judge by the two timers and the dry-run in Step 4, which is the mechanism that actually runs updates. - You see
usermod: group 'sudo' does not exist→ it means you are on a non-Ubuntu system (some distributions call the groupwheel) → this guide is Ubuntu-specific; checklsb_release -d.
Undo all of this
Tested. Firewall off:
sudo ufw disable
The important line is:
Firewall stopped and disabled on system startup
Remove the user and their files (replace the name; make sure they are logged out first):
sudo deluser --remove-home YOUR-NEW-USERNAME
Honest note from testing: if the user logged out only seconds ago, this fails with userdel: user sam is currently used by process ... — their background session takes a moment to end. Wait half a minute and run it again; that is exactly what fixed it for me. Installed updates are not something you undo.
Check it worked: id YOUR-NEW-USERNAME answers no such user, and sudo ufw status says Status: inactive.
Where to go next
- SSH keys, properly: never type a server password again — the natural next 20 minutes, and it removes the password bots' whole game.
- Official reference: Ubuntu Server documentation — security suggestions.
Last tested: 13 August 2026 on Ubuntu 24.04.4 LTS. Versions: UFW 0.36.2, unattended-upgrades 2.9.1, OpenSSH 9.6p1-3ubuntu13.18.
Tried it? Improved it?
Tell the forum what worked and what didn’t: real experience beats recommendations, and the best answers get folded back into this guide with credit.
Related guides
SSH keys, properly: never type a server password again
Your laptop will hold a small pair of files called an SSH key. Your server will trust it, so logging in never asks for a password — then we turn password logins off completely.
12 min read
Docker in 2026: install it the way Docker actually recommends
Docker installed from Docker's own package source, the way their documentation says to do it — and how to remove every trace of it, because I tested that too.
10 min read