Do these steps in order, before installing Docker or anything else. They're boring, and that's the point - get them right once and you won't think about them again.

Update the system

sudo apt update && sudo apt upgrade -y

(dnf upgrade -y on Fedora, if that's what you chose in Choosing an OS.) Reboot afterward if a kernel update was installed - sudo reboot.

Create a non-root user with sudo

If the installer didn't already set this up:

sudo adduser yourname
sudo usermod -aG sudo yourname

Debian note: if you set a root password during the Debian installer, it doesn't install sudo or add your user to the sudo group - so the commands above (and every sudo in this guide) fail with "command not found" or "not in the sudoers file." Fix it once as root, then log out and back in:

su -
apt install sudo
usermod -aG sudo yourname
exit

(If you left the root password blank in the installer, Debian sets up sudo for your user automatically, the same as Ubuntu.)

⚠️ Risk: never do your day-to-day work, and never run Docker containers, as the root user. A mistake or a compromised container has full-system consequences as root; as a sudo user, at least the blast radius is limited to what you explicitly elevate.

Set up SSH key authentication

From your everyday machine (not the server), generate a key if you don't already have one, then copy it to the server:

ssh-keygen -t ed25519 -C "[email protected]"
ssh-copy-id yourname@server-ip

Confirm you can log in with the key before the next step:

ssh yourname@server-ip

Once confirmed, disable password authentication entirely by editing /etc/ssh/sshd_config:

PasswordAuthentication no
PermitRootLogin no
sudo systemctl restart ssh

⚠️ Risk: test the key login before disabling password auth. If you disable passwords and the key doesn't work, you can lock yourself out of a headless machine. Keep a second terminal session open while you make this change so you have a way back in if something's wrong.

Give it a static IP (via DHCP reservation)

Don't set a static IP by hand on the machine itself - set a DHCP reservation on your router instead, tied to the machine's MAC address. You get a predictable IP without losing your router's central view of what's on the network. Covered in more detail in Networking Basics, but do it now so the IP doesn't change under you while you're setting everything else up.

Set up a basic firewall

ufw (Uncomplicated Firewall) is the simplest option on Debian/Ubuntu:

sudo apt install ufw
sudo ufw allow OpenSSH
sudo ufw enable

This denies all incoming connections by default except SSH. You'll add rules for specific services as you install them - do not open ports speculatively "in case you need them later."

One big exception to know about before the next page: ports published by Docker bypass ufw entirely. Docker writes its own firewall rules that take effect before ufw's, so a container started with -p 8080:80 is reachable from your network even though ufw never allowed port 8080. See Docker Essentials for what that means in practice.

⚠️ Risk: enable the firewall after explicitly allowing SSH, not before - ufw enable without an SSH allow rule first will lock out a remote session the moment it takes effect.

Set the timezone and enable automatic security updates

sudo timedatectl set-timezone Region/City
sudo apt install unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades

Automatic security updates are worth enabling on a machine you won't check daily. Full automatic upgrades (including things that might break a running service) are a judgment call - many homelabbers prefer to review those manually.

Next: Docker Essentials.