Reduce the Attack Surface First
The most effective hardening is removal — every service you don't run is a service that can't be exploited. Start from a minimal install and add only what you need. Default Linux server installs are usually lean already, but check what's listening.
# Find everything listening on network ports ss -tlnp → TCP listeners + process ss -ulnp → UDP listeners # Disable services you don't need systemctl disable bluetooth --now systemctl disable avahi-daemon --now # mDNS, rarely needed on servers systemctl disable cups --now # printing daemon # Remove packages entirely if you won't use them apt purge telnet rsh-client ftp xinetd apt autoremove
SSH Hardening
SSH is the most-attacked service on the internet. Every public IP with port 22 open is being brute-forced continuously. These changes make SSH significantly harder to attack and should be applied to every server you manage.
# /etc/ssh/sshd_config — key settings to change: Port 2222 # move off port 22 (stops script kiddie noise) PermitRootLogin no # never allow root login via SSH PasswordAuthentication no # key-only auth — most important change PubkeyAuthentication yes AuthorizedKeysFile .ssh/authorized_keys MaxAuthTries 3 LoginGraceTime 20 AllowUsers michael # whitelist specific users # After editing: sshd -t # test config before restarting systemctl restart sshd # Generate and copy your key: ssh-keygen -t ed25519 -C "homelab-key" ssh-copy-id -i ~/.ssh/id_ed25519.pub [email protected]
Firewall with UFW
UFW (Uncomplicated Firewall) wraps iptables with a sane interface. The rule: deny everything by default, explicitly allow only what you need.
# Initial setup ufw default deny incoming ufw default allow outgoing # Allow specific services ufw allow from 192.168.1.0/24 to any port 22 # SSH from LAN only ufw allow from 192.168.1.0/24 to any port 3000 # app from LAN only ufw allow 80/tcp # HTTP (for Let's Encrypt) ufw allow 443/tcp # HTTPS # Enable and check ufw enable ufw status verbose # Allow app profiles (if installed) ufw app list ufw allow 'Nginx Full'
fail2ban — Automated Ban on Brute Force
fail2ban watches log files and temporarily bans IPs that show malicious patterns — too many failed logins, too many errors, etc. It's one of the best return-on-effort security tools you can run.
apt install fail2ban # /etc/fail2ban/jail.local (override defaults here, not jail.conf) [DEFAULT] bantime = 1h findtime = 10m maxretry = 5 [sshd] enabled = true port = 2222 # match your SSH port logpath = /var/log/auth.log [nginx-http-auth] enabled = true # Commands systemctl enable --now fail2ban fail2ban-client status # see all active jails fail2ban-client status sshd # see SSH jail stats + banned IPs fail2ban-client unban 1.2.3.4 # manually unban an IP
Patch Early, Patch Often
The majority of successful attacks exploit known vulnerabilities with published patches. Staying current is the single highest-impact security action you can take.
# Manual update (Ubuntu/Debian) apt update && apt upgrade -y # Unattended security updates (installs security patches automatically) apt install unattended-upgrades dpkg-reconfigure unattended-upgrades # Check pending security updates apt list --upgradable 2>/dev/null | grep -i security # Check kernel version (kernel updates need reboot) uname -r ls /boot/vmlinuz-* # installed kernels
≈·*•—[ A|S ]—•*·≈