Initial Server Setup
SSH access, a non-root user, updates, a static IP, and a basic firewall - the handful of steps to run before anything else touches this machine.
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
rootuser. 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 enablewithout 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.