← Learn··Updated 31 May 2026·5 min read

Hardening a fresh Debian server

The first hour on a new Debian box: a sudo user, SSH key login with passwords and root disabled, automatic security updates, a firewall, and fail2ban — in the order that won't lock you out.

Homelab
Build a homelab on DebianPart 3 of 8
#homelab
#security
#ssh
#ai-assisted

level:Intermediate verified:Jun 2026

ℹ️ Hands-on — run these on your fresh Debian server over SSH. Keep a second SSH session open in case a change locks you out.

You installed Debian and you can SSH in as your user. Before this box does anything useful, spend an hour locking it down — because the moment it has a public IP, automated scanners are knocking on port 22 within minutes. Hardening a homelab server is not paranoia; it is the difference between a machine you own and a machine someone else quietly owns too. The work is small and mostly one-time, but the order matters: several of these steps can lock you out of your own server if you do them in the wrong sequence, so this post is arranged so that never happens.

⚠️ Warning — Keep a second terminal open. Through this whole post, stay logged in on one SSH session while you test changes in a new one. If a change locks out the new session, you still have the open one to undo it. Never log out of your only session right after editing SSH or firewall config.

What "hardening" actually means

Hardening is reducing a system's attack surface: fewer ways in, stronger locks on the ways that remain, and automatic patching of the locks. For a homelab server that means four concrete things — a non-root admin user, key-only SSH, automatic security updates, and a firewall — plus one nicety, fail2ban. Here is the order, and why each precedes the next:

flowchart TD
    A["Create a sudo user"] --> B["Add your SSH public key"]
    B --> C["Test key login<br/><i>new session</i>"]
    C --> D["Disable password + root login"]
    D --> E["Enable unattended-upgrades"]
    E --> F["Configure ufw<br/><i>allow SSH first</i>"]
    F --> G["Enable ufw"]
    G --> H["Install fail2ban"]

Every step depends on the one before it — keys work before passwords are disabled, SSH is allowed before the firewall turns on.

A sudo user instead of root

What sudo and the admin user are

Logging in as root means every command runs with unlimited power and nothing records who did what. The convention on every server is a regular user who can borrow root powers per-command with sudo. If you created a user during install, it may already be there; if not, create one and add it to the sudo group:

adduser mart
usermod -aG sudo mart

Log out, log back in as that user, and confirm sudo whoami prints root. From here you never log in as root again — which is also why the next steps disable root SSH entirely.

SSH keys, then disable passwords

What SSH key authentication is

A password is a secret you type (and that scanners can guess). An SSH key pair is a secret you have: a private key that never leaves your laptop and a public key you place on the server. Login succeeds only if the two halves match, so there is nothing to brute-force. This is both more secure and more convenient — no password prompt.

On your laptop (not the server), generate a key if you do not have one, then copy the public half to the server:

ssh-keygen -t ed25519
ssh-copy-id mart@your-server-ip

Now open a new terminal and ssh mart@your-server-ip. If it logs you in without asking for a password, key auth works.

Danger — Do not skip the test. Only disable password login after a fresh session has logged in with the key. If you disable passwords while your key is misconfigured, you will be locked out of the server permanently (short of console/rescue access).

With key login confirmed, harden the SSH daemon. This is a file edit, done on the server: open /etc/ssh/sshd_config (or a drop-in under /etc/ssh/sshd_config.d/) in an editor — for example sudo nano /etc/ssh/sshd_config — and make sure these two lines are present and set to no, uncommenting them if they are commented out:

PasswordAuthentication no
PermitRootLogin no

Save and close the file. Then, back at the server shell, reload SSH and test once more in yet another new session before closing your original:

sudo systemctl reload ssh
⚠️ Warning — Some hosts (cloud images especially) ship an override file in /etc/ssh/sshd_config.d/ that re-enables password auth. Setting it in the main file is not enough if a drop-in overrides it later — check that no drop-in turns PasswordAuthentication back on.

Automatic security updates

What unattended-upgrades does

A server you forget to patch is the most common way homelabs get compromised. Debian's unattended-upgrades applies security updates automatically, in the background, without you logging in. It is the single highest-value thing you can enable. Install and turn it on:

sudo apt install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades

By default it installs only the security repository, which is the safe, boring choice — exactly what you want on an always-on box (the same "boring on purpose" reason this series picked Debian for a homelab).

ℹ️ Note — Automatic security updates rarely break anything; automatic full upgrades occasionally do. Leave it on the security set unless you have a reason and a backup plan.

A firewall with ufw

What a firewall and ufw are

A firewall decides which inbound ports the machine answers on. By default a fresh server may listen on more than you think; a firewall closes everything except what you explicitly allow. ufw ("uncomplicated firewall") is Debian's friendly front-end to the kernel's netfilter.

The order here is the classic lockout trap: if you enable the firewall before allowing SSH, it drops your own connection the instant it turns on.

sudo apt install ufw
sudo ufw allow OpenSSH
sudo ufw enable
Danger — Run sudo ufw allow OpenSSH (or sudo ufw allow 22/tcp) before sudo ufw enable. Enabling ufw with no SSH rule kills your session and blocks reconnection. Allow the port you are connected on first, every time.

Open additional ports only as you add services (for example 80/tcp and 443/tcp when you set up the reverse proxy). Check the state any time with sudo ufw status.

flowchart LR
    A["Internet"] -->|"22 SSH ✓"| S["Server"]
    A -->|"80/443 later ✓"| S
    A -->|"everything else ✗"| X["dropped"]

The firewall answers only on ports you explicitly allow; everything else is silently dropped.

fail2ban for the noise

Even with key-only SSH, the logs fill with failed login attempts from bots. fail2ban watches those logs and temporarily bans IPs that fail repeatedly — it does not make you safer than key auth already does, but it cuts the noise and the load:

sudo apt install fail2ban

Its defaults protect SSH out of the box. This one is optional; everything above it is not.

💡 Tip — If you only ever do one thing from this list beyond keys, make it unattended-upgrades. Unpatched software, not weak passwords, is what actually gets homelabs popped.

A short close

A hardened Debian box is the foundation everything else in this series sits on: a non-root user, key-only SSH with root and passwords disabled, automatic security patches, a firewall that answers only where you tell it, and fail2ban mopping up the rest. Do them in the order above and you will never lock yourself out doing it. With the base secure, the next step is making it do something — Docker and Compose, the way you will run every service from here on. The whole arc is laid out in the homelab series hub.