Uncomplicated Firewall, a user-friendly frontend for iptables/nftables that simplifies host-based firewall management on Debian, Ubuntu, and other Linux distributions.
Table of Contents#
- Overview
- Architecture
- 2.1 Rule Files
- 2.2 Application Profiles
- Installation and Setup
- Basic Configuration
- Rule Syntax
- Application Profiles
- IPv6 Rules
- Rate Limiting
- Managing Rules
- 9.1 Listing Rules
- 9.2 Deleting Rules
- 9.3 Inserting Rules
- 9.4 Resetting UFW
- NAT and Port Forwarding
- 10.1 Port Forwarding
- 10.2 Masquerading
- Logging
- Testing and Verification
- Troubleshooting
- See Also
- Sources
1. Overview#
UFW (Uncomplicated Firewall) provides a simplified command-line interface for managing Linux firewall rules. It is the default firewall configuration tool on Ubuntu and is available on most other distributions. UFW operates as a frontend that generates iptables (or nftables) rules behind the scenes, making it accessible for users who do not need or want to write raw firewall rules.
Key characteristics:
- Simple syntax - human-readable commands for common firewall tasks
- Application profiles - allow traffic by application name instead of port numbers
- IPv4 and IPv6 - manages both protocol families simultaneously
- Rate limiting - built-in connection rate limiting for brute-force protection
- Persistent rules - rules survive reboots automatically
- Extensible - raw iptables rules can be added via
before.rulesandafter.rulesfiles for advanced use cases like NAT
2. Architecture#
2.1. Rule Files#
UFW stores its configuration in several files under /etc/ufw/:
| File | Purpose |
|---|---|
/etc/ufw/ufw.conf | UFW enable/disable state and logging level |
/etc/ufw/before.rules | iptables rules applied before UFW rules (IPv4) |
/etc/ufw/before6.rules | iptables rules applied before UFW rules (IPv6) |
/etc/ufw/after.rules | iptables rules applied after UFW rules (IPv4) |
/etc/ufw/after6.rules | iptables rules applied after UFW rules (IPv6) |
/etc/ufw/user.rules | Auto-generated from ufw commands (IPv4) |
/etc/ufw/user6.rules | Auto-generated from ufw commands (IPv6) |
/etc/default/ufw | Default policies and kernel module settings |
The before.rules and after.rules files are where you add raw iptables rules for features UFW does not natively support, such as NAT and port forwarding.
2.2. Application Profiles#
Application profiles are stored in /etc/ufw/applications.d/ and define port/protocol combinations for known applications. Packages that install network services (e.g., Nginx, OpenSSH, Samba) typically ship their own profile.
3. Installation and Setup#
# Debian/Ubuntu (usually preinstalled)
sudo apt install ufw
# Fedora
sudo dnf install ufw
# Arch Linux
sudo pacman -S ufw
sudo systemctl enable --now ufw4. Basic Configuration#
4.1. Enabling and Disabling#
# Enable UFW (activates rules and starts on boot)
sudo ufw enable
# Disable UFW
sudo ufw disable
# Check status
sudo ufw status
sudo ufw status verboseWarning: Enabling UFW on a remote server without first allowing SSH will lock you out. Always run
sudo ufw allow sshbeforesudo ufw enable.
4.2. Default Policies#
Default policies control traffic that does not match any explicit rule:
# Deny all incoming, allow all outgoing (recommended default)
sudo ufw default deny incoming
sudo ufw default allow outgoing
# To also control forwarded traffic
sudo ufw default deny routed4.3. Allowing Services#
# Allow by service name
sudo ufw allow ssh
sudo ufw allow http
sudo ufw allow https
# Allow by port number
sudo ufw allow 22/tcp
sudo ufw allow 53/udp
# Allow both TCP and UDP on a port
sudo ufw allow 534.4. Denying and Rejecting Traffic#
# Deny (silently drop)
sudo ufw deny 23/tcp
# Reject (send ICMP unreachable)
sudo ufw reject 23/tcp
# Deny from a specific IP
sudo ufw deny from 10.0.0.505. Rule Syntax#
5.1. Basic Rules#
# Allow incoming TCP on port 8080
sudo ufw allow 8080/tcp
# Deny incoming UDP on port 5353
sudo ufw deny 5353/udp5.2. Subnet and IP Rules#
# Allow SSH from a specific IP
sudo ufw allow from 192.168.1.100 to any port 22
# Allow from an entire subnet
sudo ufw allow from 192.168.1.0/24 to any port 22
# Allow from a subnet to a specific destination IP
sudo ufw allow from 10.0.0.0/24 to 10.0.0.1 port 443 proto tcp
# Deny from a specific IP to any destination
sudo ufw deny from 10.0.0.505.3. Interface-Specific Rules#
# Allow HTTP on a specific interface
sudo ufw allow in on eth0 to any port 80
# Allow traffic out on a specific interface
sudo ufw allow out on eth1 to any port 4435.4. Port Ranges#
# Allow a port range (must specify protocol)
sudo ufw allow 5000:6000/tcp
sudo ufw allow 5000:6000/udp6. Application Profiles#
Application profiles provide named rule sets for common services:
# List available application profiles
sudo ufw app list
# Show details of a profile
sudo ufw app info "Nginx Full"
# Allow using a profile name
sudo ufw allow "Nginx Full"
sudo ufw allow "OpenSSH"
# Deny using a profile
sudo ufw deny "Samba"Example profile output:
Profile: Nginx Full
Title: Web Server (Nginx, HTTP + HTTPS)
Description: Small, but very powerful and efficient web server
Ports:
80,443/tcpCreating Custom Profiles#
Create a file in /etc/ufw/applications.d/:
# /etc/ufw/applications.d/myapp
[MyApp]
title=My Custom Application
description=Application server on ports 8080 and 8443
ports=8080,8443/tcpThen reload and use:
sudo ufw app update MyApp
sudo ufw allow MyApp7. IPv6 Rules#
UFW handles IPv6 automatically when enabled. Verify IPv6 support is active:
# Check /etc/default/ufw
grep IPV6 /etc/default/ufw
# Should show: IPV6=yesIf IPV6=no, edit the file and set it to yes, then reload:
sudo ufw disable && sudo ufw enableWhen IPv6 is enabled, every ufw allow or ufw deny command creates rules for both IPv4 and IPv6. To create IPv6-only rules, use the full syntax:
# Allow SSH from an IPv6 address
sudo ufw allow from 2001:db8::1 to any port 22
# Allow from an IPv6 subnet
sudo ufw allow from 2001:db8::/32 to any port 4438. Rate Limiting#
UFW has a built-in rate limiting feature that denies connections from an IP address that has attempted 6 or more connections within 30 seconds. This is useful for protecting against brute-force attacks.
# Rate-limit SSH (6 attempts per 30 seconds per source IP)
sudo ufw limit ssh
# Rate-limit a specific port
sudo ufw limit 2222/tcp
# Rate-limit from specific interface
sudo ufw limit in on eth0 to any port 22The rate limit parameters (6 connections in 30 seconds) are hardcoded in UFW. For more granular rate limiting, use raw iptables rules in /etc/ufw/before.rules:
# Add to /etc/ufw/before.rules, before the COMMIT line in the *filter section:
-A ufw-before-input -p tcp --dport 22 -m state --state NEW -m recent --set --name SSH
-A ufw-before-input -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 60 --hitcount 4 --name SSH -j DROP9. Managing Rules#
9.1. Listing Rules#
# Simple status
sudo ufw status
# Verbose (shows default policies and logging)
sudo ufw status verbose
# Numbered rules (needed for deletion/insertion)
sudo ufw status numbered9.2. Deleting Rules#
# Delete by exact rule
sudo ufw delete allow ssh
sudo ufw delete allow 8080/tcp
# Delete by rule number
sudo ufw status numbered
sudo ufw delete 39.3. Inserting Rules#
Rules are evaluated top-down. Insert rules at a specific position to control priority:
# Insert a deny rule at position 1 (before all other rules)
sudo ufw insert 1 deny from 10.0.0.50
# Insert an allow rule at position 3
sudo ufw insert 3 allow from 192.168.1.0/24 to any port 229.4. Resetting UFW#
Reset removes all rules and disables UFW:
sudo ufw resetThis backs up existing rules to /etc/ufw/*.rules.YYYYMMDD_HHMMSS before removing them.
10. NAT and Port Forwarding#
UFW does not natively support NAT or port forwarding through its command-line interface. These features require editing /etc/ufw/before.rules with raw iptables rules and enabling IP forwarding.
10.1. Port Forwarding#
Step 1: Enable IP forwarding in /etc/ufw/sysctl.conf:
net/ipv4/ip_forward=1Or in /etc/sysctl.conf:
net.ipv4.ip_forward = 1Step 2: Edit /etc/ufw/before.rules and add NAT rules before the *filter section:
# NAT table rules - add at the TOP of the file, before *filter
*nat
:PREROUTING ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
# Forward port 80 to internal host 192.168.1.10
-A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to-destination 192.168.1.10:80
# Forward port 2222 to internal host SSH
-A PREROUTING -i eth0 -p tcp --dport 2222 -j DNAT --to-destination 192.168.1.10:22
COMMITStep 3: Set the default forward policy in /etc/default/ufw:
DEFAULT_FORWARD_POLICY="ACCEPT"Step 4: Allow forwarded traffic and reload:
sudo ufw allow in on eth0 to 192.168.1.10 port 80 proto tcp
sudo ufw reload10.2. Masquerading#
Add masquerading rules to /etc/ufw/before.rules in the *nat section:
*nat
:POSTROUTING ACCEPT [0:0]
# Masquerade traffic from the internal network going out eth0
-A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADE
COMMITThen reload:
sudo ufw reload11. Logging#
# Enable logging
sudo ufw logging on
# Set log level (off, low, medium, high, full)
sudo ufw logging medium
# Disable logging
sudo ufw logging offLog levels:
| Level | Description |
|---|---|
off | No logging |
low | Log blocked packets not matching default policy, and rate-limited packets |
medium | Low, plus invalid packets, new connections, and logged packets |
high | Medium, plus all packets with rate limiting |
full | All packets without rate limiting |
Logs are written to /var/log/ufw.log (on systems using rsyslog) and are also available via:
# View recent UFW log entries
journalctl -k --grep="UFW"
# Follow log in real time
sudo tail -f /var/log/ufw.log12. Testing and Verification#
# Check UFW status and active rules
sudo ufw status verbose
# List numbered rules
sudo ufw status numbered
# Test port from another host
nc -zv <server-ip> 80
# Scan with nmap from another host
nmap -p 22,80,443 <server-ip>
# Show the raw iptables rules UFW generated
sudo iptables -L -v -n
sudo iptables -t nat -L -v -n
# Verify UFW is enabled on boot
systemctl is-enabled ufwTroubleshooting#
| Issue | Cause | Solution |
|---|---|---|
| Locked out after enabling UFW | SSH not allowed before enabling | Use console access; boot to recovery; or use ufw --force reset from single-user mode |
| Rules not taking effect | UFW not enabled | Run sudo ufw enable |
| Port forwarding not working | NAT rules not in before.rules or IP forwarding disabled | Edit /etc/ufw/before.rules, enable ip_forward in sysctl, set DEFAULT_FORWARD_POLICY="ACCEPT" |
| IPv6 traffic bypassing rules | IPv6 disabled in UFW config | Set IPV6=yes in /etc/default/ufw, then reload |
| Rate limit too strict/lenient | Hardcoded 6/30s in UFW limit | Use raw iptables rules in before.rules for custom rate limits |
| Application profile not found | Package did not install a profile | Create a custom profile in /etc/ufw/applications.d/ |
| Docker bypasses UFW rules | Docker manipulates iptables directly | Use DOCKER_IPTABLES=false in Docker config, or add rules to the DOCKER-USER chain in after.rules |
| UFW conflicts with FirewallD | Both managing the same backend | Use only one; disable the other with systemctl disable |
before.rules syntax error | Missing COMMIT or malformed rule | Check for matching *table/COMMIT pairs; run sudo ufw reload and check syslog for errors |
See Also#
Sources#
- Ubuntu UFW Documentation
- Ubuntu Server Guide - Firewall
- Arch Wiki - UFW
man ufwman ufw-framework