System Hardening — Secure Defaults, Services, Updates, Logging

Reducing attack surface by securing systems at the foundational level.

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 ]—•*·≈

- Crafted by Axiom|Spectre