Configure Personal Firewall Easily
Running a homelab exposes you to real security risks. Whether you're self-hosting Nextcloud, Jellyfin, or just SSH access, a misconfigured firewall is like leaving your front door unlocked. I've learned the hard way that port scanning happens within minutes of going online, and attackers are relentless. In this guide, I'll show you how to set up UFW (Uncomplicated Firewall), configure fail2ban to block brute-force attacks, and harden SSH—all the essentials I use on every server I deploy.
Why You Need a Firewall on Your Homelab
If you think "I'm behind NAT" or "nobody knows my IP," you're wrong. Automated scanners hit every IP on the internet looking for open ports and vulnerable services. I've seen SSH brute-force attempts log hundreds of failed login attempts per hour on unprotected servers. A firewall isn't just about blocking traffic—it's about being selective about what you expose.
The three layers I always implement are:
- Stateful firewall rules (UFW) – deny by default, allow only what you need
- Fail2ban – automatic ban for repeated failed login attempts
- SSH hardening – disable root login, use key authentication, change the default port
These three tools work together to make your server a much harder target.
Setting Up UFW: The Right Way
UFW is my go-to firewall on Ubuntu and Debian. It sits on top of iptables but is far easier to reason about. When I first set up a VPS (I recommend checking out RackNerd KVM VPS for solid bang-for-buck pricing if you want offsite hardware), UFW is the first thing I enable.
Here's the correct sequence:
# 1. Install UFW (usually pre-installed on Ubuntu)
sudo apt update && sudo apt install -y ufw
# 2. Set default policies (deny incoming, allow outgoing)
sudo ufw default deny incoming
sudo ufw default allow outgoing
# 3. Allow SSH before enabling UFW (CRITICAL—don't lock yourself out!)
sudo ufw allow 22/tcp
# 4. Allow HTTP and HTTPS (if running a web service)
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# 5. Enable the firewall
sudo ufw enable
# 6. Verify rules are in place
sudo ufw status verbose
ufw enable. If you do lock yourself out, you'll need console access or a reboot into recovery mode.After enabling, check the status with sudo ufw status numbered. You should see something like this:
To Action From
-- ------ ----
[ 1] 22/tcp ALLOW IN Anywhere
[ 2] 80/tcp ALLOW IN Anywhere
[ 3] 443/tcp ALLOW IN Anywhere
I prefer numbered output because it makes deleting rules easier. If you mess up and add a duplicate, delete it with sudo ufw delete 2 (where 2 is the rule number).
Blocking Brute-Force Attacks with fail2ban
UFW stops random port scans, but fail2ban stops targeted attacks. When someone (or a bot) makes repeated failed SSH login attempts, fail2ban automatically bans that IP for a set period. I installed fail2ban on every server after my second password-guessing attack within a week.
# 1. Install fail2ban
sudo apt install -y fail2ban
# 2. Create a local config (don't edit jail.conf directly—it updates)
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
# 3. Edit the local config
sudo nano /etc/fail2ban/jail.local
# Key settings to adjust:
# bantime = 3600 (ban for 1 hour)
# findtime = 600 (within 10 minutes)
# maxretry = 5 (5 failed attempts triggers ban)
# 4. Enable the SSH jail specifically
sudo nano /etc/fail2ban/jail.d/ssh.local
Create or edit /etc/fail2ban/jail.d/ssh.local with these contents:
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 5
findtime = 600
bantime = 3600
Then restart and check:
# Restart fail2ban
sudo systemctl restart fail2ban
# Check if the SSH jail is active
sudo fail2ban-client status sshd
# You should see output like:
# Status for the jail: sshd
# |- Filter file list: sshd
# |- Currently failed: 0
# |- Currently banned: 0
# `- Total banned: 0
Now, if an attacker tries 5 failed logins within 10 minutes, they're automatically banned for an hour. I've watched this work in real time—IP addresses that were pounding my server suddenly go quiet.
Hardening SSH: The Foundation
Even with fail2ban, SSH is your biggest attack surface. I always apply these hardening rules:
# Edit SSH config
sudo nano /etc/ssh/sshd_config
# Find and change (or add) these lines:
# PermitRootLogin no (never allow root SSH login)
# PasswordAuthentication no (use keys only)
# PubkeyAuthentication yes (enable key auth)
# PermitEmptyPasswords no (already default)
# MaxAuthTries 3 (reduce brute-force window)
# Port 2222 (change from 22 to something less obvious)
# After editing, test the config for syntax errors
sudo sshd -t
# If no errors, restart SSH
sudo systemctl restart ssh
# Generate an SSH key on your local machine (if you haven't)
# Run this on your laptop/desktop, NOT on the server
ssh-keygen -t ed25519 -C "myserver-key" -f ~/.ssh/id_ed25519_homelab
# Copy the public key to your server (password login still works temporarily)
ssh-copy-id -i ~/.ssh/id_ed25519_homelab.pub -p 2222 username@your-server-ip
# Test the key login works before disabling passwords
ssh -i ~/.ssh/id_ed25519_homelab -p 2222 username@your-server-ip
sudo ufw allow 2222/tcp and sudo ufw delete allow 22/tcp. Keep the old rule there while testing, then delete it once you confirm key auth works.Testing Your Setup
Once everything is in place, test it. From a different machine, try to SSH with the wrong key or password. You should be rejected immediately. After 3 failed attempts (or whatever you set in fail2ban), fail2ban should ban that IP. Check the ban with:
sudo fail2ban-client status sshd
You'll see banned IPs listed. To manually unban for testing:
sudo fail2ban-client set sshd unbanip 192.168.1.100
Managing Rules Long-Term
After a few months, you'll want to audit what you've allowed. I run this quarterly:
sudo ufw status numbered
Remove anything you no longer need. If you're no longer running a specific service, close the port. Each open port is another potential vulnerability. I also recommend logging what fail2ban is doing:
sudo tail -f /var/log/fail2ban.log
This shows bans in real-time, which is strangely satisfying and also reassuring—you see active threats being blocked.
Integration with Self-Hosted Services
If you're running Nextcloud, Jellyfin, or other services behind a reverse proxy like Caddy or Nginx, remember that the firewall protects at the system level, but fail2ban can also watch your application logs. For Nextcloud brute-force protection, create a jail that monitors /var/log/nextcloud/nextcloud.log. The principle is the same: detect failures, ban IPs, repeat.
Final Checklist
- UFW default-deny setup with only required ports open
- fail2ban installed and SSH jail enabled
- SSH key auth configured, password auth disabled
- SSH port changed from 22 to something else
- Root SSH login disabled
- Firewall rules verified with
ufw status - fail2ban status checked with
fail2ban-client status sshd
This is the bare minimum I deploy on every server. It's not perfect security, but it eliminates 99% of automated attacks and makes you a harder target than unprotected systems. Combined with good practices like regular updates and SSH key rotation, you've built a solid foundation for a secure homelab.