Every time I expose a Linux machine to the internet I run through the same checklist. These are not theoretical controls — they are the minimum I apply before any service goes live.
1. Disable root login and password auth
# /etc/ssh/sshd_config
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
Generate a key pair locally, copy the public key, then restart sshd:
ssh-keygen -t ed25519 -C "homelab"
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server
sudo systemctl restart sshd
2. UFW — allow only what you need
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp # SSH — change to your port
sudo ufw enable
Never open port ranges. Never use ufw allow from any. Be explicit.
3. fail2ban
Blocks IPs after repeated failed auth attempts:
sudo apt install fail2ban
# /etc/fail2ban/jail.local
[sshd]
enabled = true
port = 22
maxretry = 3
bantime = 1h
findtime = 10m
sudo systemctl enable --now fail2ban
4. Unattended security upgrades
sudo apt install unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades
This auto-applies security patches daily without touching non-security packages.
5. Audit with Lynis
Lynis is an open-source security auditing tool that scores your system against CIS benchmarks:
sudo apt install lynis
sudo lynis audit system
Aim for a hardening index above 70. Common quick wins: disable unused kernel modules, restrict /proc mount options, enable auditd.
6. Change the SSH port
Not real security, but it eliminates 99% of automated scan noise in your logs:
# /etc/ssh/sshd_config
Port 2222
Update UFW to allow the new port before restarting sshd — or you will lock yourself out.
What I skip (and why)
- SELinux/AppArmor profiles for every service — useful but high maintenance. I use AppArmor only for internet-facing services.
- Port knocking — adds friction without meaningful security if you already have key-only auth + fail2ban.
Security is a process, not a checklist. Run Lynis monthly and re-evaluate after any major config change.