What is UFW?
UFW is a command-line interface to iptables, which is the Linux kernel's packet filtering engine. You do not need to understand iptables to use UFW. That is the point.
It ships with Ubuntu since version 8.04 and is available on all Debian-based distributions: Debian, Raspberry Pi OS, Ubuntu Server. The package is called ufw. Check if it is installed:
sudo ufw version
# Should return something like: ufw 0.36.1
If not installed:
sudo apt update && sudo apt install -y ufw
UFW is not enabled by default. Run sudo ufw status and you will most likely see Status: inactive. That is what we are fixing.
sudo ufw allow ssh before you run sudo ufw enable. Skip this on a remote server and you lock yourself out with no way back in without physical access to the machine.
Default policy: deny all incoming
Start with two rules that cover all traffic you do not explicitly allow:
sudo ufw default deny incoming # block all inbound by default
sudo ufw default allow outgoing # allow all outbound by default
These two lines are the foundation. Everything you add after is an exception to the inbound rule.
Allow SSH before anything else
Do this now, before enabling the firewall:
# Short form (uses /etc/services to look up port 22)
sudo ufw allow ssh
# Or explicit:
sudo ufw allow 22/tcp
Allow the services you actually run
Open only the ports you use. Examples:
# HTTP and HTTPS (web server)
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# DNS (Pi-hole or AdGuard Home)
sudo ufw allow 53
# WireGuard VPN
sudo ufw allow 51820/udp
# AdGuard Home initial setup port (only needed during setup)
sudo ufw allow 3000/tcp
Named profiles
UFW supports named profiles for known applications. Profiles live in /etc/ufw/applications.d/. List what is available:
sudo ufw app list
Allow a profile:
sudo ufw allow "OpenSSH" # SSH via named profile
sudo ufw allow "Nginx Full" # HTTP + HTTPS via named profile
LAN restriction: allow only from your local network
Instead of opening a port to the whole internet, you can restrict access to your LAN subnet. This is good practice for SSH, DNS and admin interfaces:
# SSH from 192.168.1.x only
sudo ufw allow from 192.168.1.0/24 to any port 22
# DNS from LAN only
sudo ufw allow from 192.168.1.0/24 to any port 53
# Pi-hole admin (port 80) from LAN only
sudo ufw allow from 192.168.1.0/24 to any port 80
Adjust 192.168.1.0/24 to your actual subnet. Check with ip route and look for the line starting with your LAN interface (typically eth0 or wlan0).
Enable the firewall
Once your rules are in place:
sudo ufw enable
UFW asks for confirmation. Type y. The firewall is now active and persists across reboots automatically.
Check status and rules
sudo ufw status verbose
Output shows active rules, default policies and IPv6 status. verbose gives more detail than plain status.
From another machine on LAN you can verify with nmap:
nmap -p 22,53,80,443 [your-pi-ip]
Ports you opened should show as open. Ports you did not open should show as filtered.
Rate limiting SSH
UFW can rate-limit SSH connections: addresses that exceed 6 attempts in 30 seconds get temporarily blocked. One command:
sudo ufw limit ssh
It is not a full replacement for fail2ban, but it is considerably better than nothing and requires zero configuration.
Delete rules
Delete a rule using the exact syntax you used to add it:
sudo ufw delete allow 80/tcp
Alternatively, delete by rule number:
sudo ufw status numbered # show rules with numbers
sudo ufw delete 3 # delete rule number 3
Logging
UFW can log blocked traffic to /var/log/ufw.log:
sudo ufw logging on
Use low, medium or high to control the volume of log output. on is equivalent to low. Watch the log live:
sudo tail -f /var/log/ufw.log
IPv6
UFW supports IPv6. Check that IPV6=yes is set in /etc/default/ufw. It is the default on modern systems, but worth verifying:
grep IPV6 /etc/default/ufw
# Should return: IPV6=yes
When IPv6 is enabled, UFW automatically creates corresponding IPv6 rules for any port you open.
Complete Pi homelab example
A Raspberry Pi running Pi-hole and SSH, accessible only from LAN. From scratch:
# Set default policy
sudo ufw default deny incoming
sudo ufw default allow outgoing
# SSH from LAN only (do this BEFORE enable)
sudo ufw allow from 192.168.1.0/24 to any port 22
# DNS from LAN (Pi-hole/AdGuard)
sudo ufw allow from 192.168.1.0/24 to any port 53
# Pi-hole admin interface from LAN
sudo ufw allow from 192.168.1.0/24 to any port 80
# Rate limit SSH
sudo ufw limit ssh
# Enable logging
sudo ufw logging on
# Enable
sudo ufw enable
# Verify
sudo ufw status verbose
sudo ufw delete allow 3000/tcp.
What UFW does not do
UFW is a network firewall tool. It is not an intrusion detection system. It does not inspect packet contents. It has no idea whether the traffic passing through port 22 is actually SSH or something else that happens to use that port.
It does not protect against attacks from machines on your own LAN. If you have LAN rules open for 192.168.1.0/24, any device on that network can reach those ports.
It is not a replacement for a VPN for remote access. If you need secure access to your network from outside, WireGuard is the right tool.
Sources
- UFW – Ubuntu Community Documentation: official documentation with examples and advanced use cases
- ufw(8) man page – Ubuntu Manpages: complete command reference for all UFW options
- Uncomplicated Firewall (ufw) – Debian Wiki: Debian-specific setup and configuration details