NeuroDynamic.Tech
Sign inJoin

First hour with a new Ubuntu server: locking the doors

A fully updated server, a personal account with admin rights, a firewall that blocks everything except SSH, and security updates that install themselves.

The founder · 10 min read ·

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 apt command.
  • 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-IP below 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 out on 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, run sudo 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-upgrades report disabled → 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 group wheel) → this guide is Ubuntu-specific; check lsb_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


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