Configure Personal Firewall

Configure Personal Firewall: UFW & Fail2Ban for Linux Homelab

When I first exposed a self-hosted service to the internet, I learned the hard way: a firewall isn't optional. Within hours of opening port 22 without protection, my logs showed thousands of SSH brute-force attempts. That's when I realized I needed both UFW (Uncomplicated Firewall) and Fail2Ban working together. This guide walks you through setting up both, with real commands I use in production.

Why Both UFW and Fail2Ban?

UFW is your perimeter defense—it decides which ports are open and which traffic is allowed. Fail2Ban is your active guard—it watches logs and bans IPs that show malicious behavior. I prefer this two-layer approach because UFW alone won't stop a targeted brute-force attack, and Fail2Ban without UFW leaves unnecessary ports exposed.

Think of it like this: UFW is the locked door, Fail2Ban is the security camera that calls the police when someone tries to pick the lock too many times.

Step 1: Install and Configure UFW

Most Debian and Ubuntu systems come with UFW preinstalled but disabled. Let's enable it and open only what we need.

sudo ufw status
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable

This sets the foundation: deny everything coming in by default, allow everything going out (so your system can reach the internet), then explicitly allow SSH, HTTP, and HTTPS. The allow 22/tcp is critical—if you lock yourself out of SSH, you'll need physical access to recover.

If you're running a specific homelab service like Nextcloud or Jellyfin, add those ports too:

sudo ufw allow 8080/tcp
sudo ufw allow 8443/tcp
sudo ufw status numbered

The numbered output shows each rule with a number, making it easy to delete rules later if needed.

Watch out: Don't enable UFW and then immediately lock yourself out. Test SSH access in another terminal before closing your current session. If you're on a VPS (like RackNerd KVM) with a console, you have a recovery path. Home machines? You might not.

Step 2: Install and Configure Fail2Ban

Fail2Ban monitors logs and bans IPs after repeated failed login attempts. Install it first:

sudo apt-get update
sudo apt-get install fail2ban -y

Fail2Ban works by reading log files and applying firewall rules. The default SSH jail is good, but I always customize it. Create a local override file instead of editing the main config:

sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo nano /etc/fail2ban/jail.local

Find the [sshd] section and modify these values:

[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 5
findtime = 600
bantime = 3600

What this does: after 5 failed login attempts within 10 minutes (600 seconds), ban that IP for 1 hour (3600 seconds). I prefer being strict here—automated attackers don't care about legitimate timeouts.

Save and exit, then restart Fail2Ban:

sudo systemctl restart fail2ban
sudo fail2ban-client status sshd

You should see output like:

Status for the jail sshd:
|- Filter
|  |- Currently failed: 0
|  |- Total failed: 0
|  `- Journal matches: 0
`- Actions
   |- Currently banned: 0
   |- Total banned: 0
   `- Banned IP list:
Tip: To manually unban an IP (for testing or mistakes), run: sudo fail2ban-client set sshd unbanip 192.168.1.100. Replace the IP with the actual address.

Step 3: Add Custom Jails for Your Services

If you're running Nextcloud, Vaultwarden, or other web apps, create jails to protect them. Here's a Nextcloud example:

sudo nano /etc/fail2ban/jail.d/nextcloud.local

Add this:

[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 5

[nextcloud]
enabled = true
port = http,https
filter = nextcloud
logpath = /var/www/nextcloud/data/nextcloud.log
maxretry = 3

Then create the filter file:

sudo nano /etc/fail2ban/filter.d/nextcloud.local

Add:

[Definition]
failregex = ^.*Login attempt with non-existent user.*"uid":"".*$
            ^.*Auth token attempt.*"uid":"".*$
ignoreregex =

Restart Fail2Ban and verify:

sudo systemctl restart fail2ban
sudo fail2ban-client status

Step 4: Monitor and Maintain

Firewalls need attention. I check my logs weekly. View current bans:

sudo fail2ban-client status
sudo fail2ban-client status sshd

To see what Fail2Ban is catching:

sudo tail -f /var/log/fail2ban.log

This is enlightening—you'll see the attack traffic attempting everything from default usernames to exploit paths. It's a good reminder why this matters.

For UFW, check periodically:

sudo ufw status verbose

Integrating with Homelab Infrastructure

If you're running multiple services behind a reverse proxy like Caddy or Nginx Proxy Manager, your firewall should still be the outermost layer. Keep UFW rules simple at the firewall level, and let your reverse proxy handle application-specific routing.

For a small VPS hosting multiple sites (like a budget RackNerd KVM instance), you might open 80 and 443 globally, then rely on Fail2Ban to protect SSH and any admin interfaces running on unusual ports.

Quick Security Checklist

Wrapping Up

UFW + Fail2Ban is a proven, lightweight approach to firewall hardening. I've been using this exact setup across a dozen self-hosted machines for three years without a single compromise. The key is that UFW handles the static policy (what's allowed), while Fail2Ban handles dynamic threats (who's trying to abuse what's allowed).

Next steps: enable these services, set them to start on boot (they do by default), and check your logs regularly. Your homelab will be significantly safer for a few minutes of setup.

```