UFW vs firewalld: How to Pick the Right Linux Firewall Manager
Linux firewall management has evolved into two distinct camps, and which one you encounter often depends on the distribution you're running. UFW dominates the Debian and Ubuntu world, while firewalld has become the standard on Red Hat-based systems.
UFW (Uncomplicated Firewall) really is uncomplicated. It keeps things simple, uses easy commands that read like normal English, and focuses on basic security without giving you too many options to worry about.
Firewalld works in a different way. It organizes your firewall around zones, such as trusted networks, public interfaces, and DMZ segments, and it manages rules inside these zones. This fits complex network setups better, but it also makes the tool harder to understand.
Both tools ultimately control the same underlying system, but they take such different paths that switching between them requires rethinking how you approach firewall management. This guide breaks down both tools so you can understand which one fits your environment better.
Understanding UFW's approach
UFW appeared on Ubuntu systems to solve a specific problem: people weren't configuring firewalls because iptables was too intimidating. The solution was to strip away complexity and focus on the most common security tasks.
The core design is intentionally minimal. You open ports, close ports, allow addresses, deny addresses. That's most of what you do, and UFW makes those operations dead simple:
sudo ufw allow 80
sudo ufw deny from 203.0.113.50
There's no concept of zones or services in UFW's basic model. A firewall rule is just "let this through" or "block that." This simplicity means less to learn but also less sophisticated organization for complex setups.
UFW comes pre-installed on Ubuntu and many Debian-based distributions. It sits dormant until you enable it, which means your server isn't protected by default but also won't interfere with whatever you're trying to set up initially. The tool handles both IPv4 and IPv6 automatically, creating parallel rules for both without you having to think about it.
Now that you understand UFW's philosophy of simplicity, you can see how firewalld takes a completely different approach by organizing security around network zones.
How firewalld organizes security
Firewalld came from the Red Hat ecosystem with a different set of assumptions. Instead of treating all networks the same, it acknowledges that you probably trust your home network more than a coffee shop WiFi, and your corporate LAN more than the internet.
This leads to zones - predefined security levels that group rules together. Each network interface gets assigned to a zone, and the zone determines what's allowed. The default zones include:
- public: Untrusted networks where you only allow specific services
- home: Trusted networks where you're more permissive
- work: Corporate networks with moderate restrictions
- dmz: Demilitarized zones for public-facing services
- trusted: Completely trusted, everything allowed
When you add a rule in firewalld, you specify which zone it applies to. This means you can have different rules for your internal network interface versus your external one, all managed through a unified system.
Firewalld also thinks in terms of services rather than just ports. Instead of remembering that SSH is port 22, you just reference the SSH service:
sudo firewall-cmd --zone=public --add-service=ssh
The service definitions live in XML files that specify all the ports and protocols that service needs. You can create custom services for your applications instead of memorizing port numbers.
With both approaches now clear, examining their differences side by side will help you see which model matches your infrastructure needs.
Comparing the fundamentals
Looking at these tools side by side reveals their different philosophies and practical implications:
| Feature | UFW | firewalld |
|---|---|---|
| Primary distribution | Ubuntu, Debian | RHEL, Fedora, CentOS |
| Organizational model | Flat rule list | Zone-based hierarchy |
| Default state | Disabled | Active on RHEL systems |
| Configuration method | Command-line only | CLI and GUI (firewall-config) |
| Service definitions | Application profiles (optional) | XML service files (central) |
| Runtime vs permanent | Changes are permanent | Separate runtime/permanent configs |
| Network interface handling | Manual per-rule specification | Zone assignments per interface |
| Rich rules | Not supported | Complex multi-criteria rules |
| Direct rules | Not available | Passthrough to iptables |
| IPv6 handling | Automatic parallel rules | Integrated in zones |
| Configuration files | Simple text rules | XML configuration |
| Logging integration | Basic ufw.log | journald integration |
| Dynamic reconfiguration | Requires reload | Live changes without disruption |
| Desktop integration | None | NetworkManager integration |
| Masquerading/NAT | Basic syntax | Advanced zone-based NAT |
| Port forwarding | Requires custom rules | Built-in rich rule syntax |
These architectural differences become clearer when you start creating actual firewall rules, so let's look at how UFW handles this in practice.
Creating rules in UFW
UFW keeps firewall management focused on the essentials. The basic operations cover what most servers need without branching into specialized networking features.
Opening a port for everyone is one line:
sudo ufw allow 443
If you want to specify the protocol:
sudo ufw allow 443/tcp
Limiting access to specific addresses adds a from clause:
sudo ufw allow from 192.168.1.0/24 to any port 22
You can reference application profiles instead of ports:
sudo ufw allow 'Apache Full'
These profiles live in /etc/ufw/applications.d/ and define what ports applications need. The Apache Full profile, for example, opens both port 80 and 443.
Removing rules mirrors adding them:
sudo ufw delete allow 443/tcp
Or you can work with rule numbers:
sudo ufw status numbered
Status: active
To Action From
-- ------ ----
[ 1] 22 ALLOW IN 192.168.1.0/24
[ 2] 443/tcp ALLOW IN Anywhere
[ 3] Apache Full ALLOW IN Anywhere
sudo ufw delete 2
Checking your configuration shows a clean table:
sudo ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip
To Action From
-- ------ ----
22 ALLOW IN 192.168.1.0/24
Apache Full ALLOW IN Anywhere
The straightforward syntax means you can usually guess the correct command without consulting documentation. But this simplicity has limits when you need complex scenarios that don't fit UFW's model.
Having seen UFW's flat rule approach, you're ready to explore how firewalld's zone-based model changes the way you think about firewall rules.
Managing zones in firewalld
Firewalld's zones create a mental model where different network connections have different trust levels and therefore different rules.
Checking which zones exist on your system:
sudo firewall-cmd --get-zones
block dmz drop external home internal public trusted work
Each interface on your system gets assigned to a zone. Seeing current assignments:
sudo firewall-cmd --get-active-zones
public
interfaces: eth0
internal
interfaces: eth1
This output tells you eth0 (probably your internet connection) uses the public zone, while eth1 (maybe your internal network) uses the internal zone.
Adding a service to a zone opens those ports on that interface:
sudo firewall-cmd --zone=public --add-service=http
This change takes effect immediately but doesn't survive a reboot. Making it permanent requires the --permanent flag:
sudo firewall-cmd --zone=public --add-service=http --permanent
You can also make temporary changes permanent after testing:
sudo firewall-cmd --runtime-to-permanent
Opening a port directly instead of using a service:
sudo firewall-cmd --zone=public --add-port=8080/tcp --permanent
Seeing what's currently allowed in a zone:
sudo firewall-cmd --zone=public --list-all
public (active)
target: default
icmp-block-inversion: no
interfaces: eth0
sources:
services: dhcpv6-client http ssh
ports: 8080/tcp
protocols:
forward: no
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
This detailed output shows everything about the zone - which interfaces use it, what services are allowed, any custom ports, and advanced configurations. The zone model adds complexity but provides better organization when you're managing multiple network interfaces with different security requirements.
You've now seen how both tools create basic rules, but their approaches to service definitions reveal even deeper philosophical differences.
Service definitions and management
How these tools handle services shows a fundamental difference in philosophy.
UFW treats services as optional conveniences. You can use application profiles, but they're just shortcuts for port numbers:
sudo ufw app list
Available applications:
Apache
Apache Full
Apache Secure
OpenSSH
Postfix
Postfix SMTPS
Postfix Submission
Each profile is a simple text file:
[Apache]
title=Web Server
description=Apache v2 is the next generation of the omnipresent Apache web server.
ports=80/tcp
[Apache Full]
title=Web Server (HTTP,HTTPS)
description=Apache v2 is the next generation of the omnipresent Apache web server.
ports=80,443/tcp
[Apache Secure]
title=Web Server (HTTPS)
description=Apache v2 is the next generation of the omnipresent Apache web server.
ports=443/tcp
You can create custom profiles easily, but many users skip this and just work with ports directly.
Firewalld makes services central to its model. Checking available services:
sudo firewall-cmd --get-services
RH-Satellite-6 amanda-client amanda-k5-client amqp amqps apcupsd audit bacula bacula-client bgp bitcoin bitcoin-rpc bitcoin-testnet bitcoin-testnet-rpc ceph ceph-mon cfengine condor-collector ctdb dhcp dhcpv6 dhcpv6-client distcc dns docker-registry docker-swarm dropbox-lansync elasticsearch etcd-client etcd-server finger freeipa-ldap freeipa-ldaps freeipa-replication freeipa-trust ftp...
Each service is an XML file in /usr/lib/firewalld/services/. Looking at the SSH service:
<?xml version="1.0" encoding="utf-8"?>
<service>
<short>SSH</short>
<description>Secure Shell (SSH) is a protocol for logging into and executing commands on remote machines. It provides secure encrypted communications.</description>
<port protocol="tcp" port="22"/>
</service>
Creating a custom service means creating an XML file:
<?xml version="1.0" encoding="utf-8"?>
<service>
<short>MyApp</short>
<description>Custom application service</description>
<port protocol="tcp" port="8080"/>
<port protocol="tcp" port="8443"/>
</service>
Then reload firewalld to pick up the new service:
sudo firewall-cmd --reload
Now you can use it like any other service:
sudo firewall-cmd --zone=public --add-service=myapp --permanent
The service-centric approach encourages better documentation of what ports your applications use and why, but it requires more upfront work. With basic rule creation covered, you're ready to see where these tools really diverge - in handling advanced networking scenarios.
Handling advanced scenarios
Where these tools really diverge is in handling situations beyond basic port management.
UFW keeps things simple, which means some advanced configurations require dropping down to iptables rules. Port forwarding, for example, needs editing UFW's configuration files directly:
# NAT table rules
*nat
:PREROUTING ACCEPT [0:0]
# Forward port 80 to internal server
-A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to-destination 192.168.1.100:80
# Don't forget to commit the rules
COMMIT
Then you need to enable forwarding in UFW's configuration:
DEFAULT_FORWARD_POLICY="ACCEPT"
And enable kernel IP forwarding:
net.ipv4.ip_forward=1
This works, but you're basically writing iptables rules, which defeats UFW's purpose.
Firewalld handles port forwarding natively through rich rules:
sudo firewall-cmd --zone=public --add-forward-port=port=80:proto=tcp:toport=8080:toaddr=192.168.1.100 --permanent
That one command sets up the forwarding, and firewalld manages all the underlying netfilter configuration.
Rich rules in firewalld let you create complex conditions:
sudo firewall-cmd --zone=public --add-rich-rule='rule family="ipv4" source address="10.0.0.0/8" service name="ssh" log prefix="SSH-Access" level="info" accept' --permanent
This rule allows SSH from 10.0.0.0/8 and logs every connection with a custom prefix. Building something equivalent in UFW requires manual iptables rules.
Masquerading (NAT for internet sharing) is simple in firewalld:
sudo firewall-cmd --zone=external --add-masquerade --permanent
UFW requires similar manual configuration as port forwarding. The complexity difference becomes clear when you need these features - firewalld includes them as first-class functionality, while UFW expects you to extend it manually.
Understanding these advanced capabilities matters, but how each tool saves and manages configuration changes affects your daily workflow even more significantly.
Configuration persistence and changes
How these tools handle saving your configuration affects how you work with them day-to-day.
UFW makes every change permanent immediately. When you run:
sudo ufw allow 80
That rule gets written to disk right away. There's no separate step to save your work. This is simple but means you can't easily test changes before committing them.
You can disable UFW to test something:
sudo ufw disable
Make your system changes, verify everything works, then re-enable:
sudo ufw enable
But this is all-or-nothing - you're either protected or not.
Firewalld separates runtime and permanent configurations. A change without --permanent takes effect immediately but disappears after reload or reboot:
sudo firewall-cmd --zone=public --add-service=http
This lets you test whether opening port 80 fixes your problem. If it works, make it permanent:
sudo firewall-cmd --zone=public --add-service=http --permanent
Or make all runtime changes permanent at once:
sudo firewall-cmd --runtime-to-permanent
If something breaks, reload to get back to your permanent configuration:
sudo firewall-cmd --reload
This two-tier approach feels more complex initially but provides valuable safety when making changes to production systems. You can experiment without risking your permanent security configuration.
Firewalld also supports complete configuration snapshots. Before major changes:
sudo firewall-cmd --zone=public --list-all > /backup/firewall-config-$(date +%Y%m%d).txt
UFW's configuration lives in simple text files in /etc/ufw/, which you can version control:
sudo tar -czf /backup/ufw-config-$(date +%Y%m%d).tar.gz /etc/ufw
Both approaches work, but firewalld's runtime/permanent split gives you more granular control over when changes become permanent. Beyond just configuration management, how these tools integrate with the broader Linux ecosystem impacts your overall administrative experience.
Integration with system tools
How firewalls interact with other system components affects your overall experience managing servers.
UFW is intentionally standalone. It doesn't integrate deeply with other tools, which makes it simple but sometimes disconnected. NetworkManager doesn't interact with UFW, so your firewall configuration stays the same whether you're on WiFi, ethernet, or VPN.
This consistency is good for servers that don't change networks, but it's inflexible for laptops that move between trusted home networks and untrusted public WiFi.
Firewalld integrates tightly with NetworkManager on desktop systems. When you mark a WiFi network as "home" in NetworkManager, firewalld automatically uses your home zone for that connection. Switch to public WiFi, and firewalld moves to the public zone.
This integration makes firewalld more complex to understand because there are more moving parts, but it's more powerful for systems that change network contexts frequently.
Firewalld also integrates with systemd's journal for logging:
sudo journalctl -u firewalld
Nov 27 14:32:15 server firewalld[1234]: WARNING: COMMAND_FAILED: '/usr/sbin/iptables-restore -w -n' failed: iptables-restore v1.8.4 (nf_tables)
Nov 27 14:32:18 server firewalld[1234]: DEFAULT_ZONE_CHANGED: public
Nov 27 14:32:20 server firewalld[1234]: ZONE_SERVICE_ADDED: public http
UFW logs to /var/log/ufw.log, which is simpler but less integrated with modern logging infrastructure.
For GUI management, firewalld includes firewall-config, a graphical tool for zone and rule management. UFW has third-party GUI tools like GUFW, but they're not official and not as feature-complete. These integration differences matter more on desktop systems than servers, but they affect the overall ecosystem around each tool.
With technical differences established, the practical question becomes how quickly you can become productive with each tool.
Learning curve and daily usage
Getting productive with these tools requires different initial investments.
UFW's learning curve is gentle. The basic commands make intuitive sense:
sudo ufw enable
sudo ufw allow 22
sudo ufw status
You can start securing your server within minutes of first encountering UFW. The challenge comes later when you need something UFW doesn't directly support.
Firewalld requires understanding zones before you're productive. Which zone should you use? What's the difference between public and external? Do you need separate zones for different interfaces?
These questions take time to answer, but once you understand the model, it becomes powerful. The initial investment pays off when you're managing complex network configurations.
Command complexity also differs. UFW commands are short:
sudo ufw allow from 10.0.0.0/8 to any port 22
Firewalld commands are more verbose:
sudo firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="10.0.0.0/8" port port=22 protocol=tcp accept'
The extra verbosity provides more control but takes longer to type and remember.
Daily usage patterns differ too. With UFW, you mostly add and remove rules:
sudo ufw allow 8080/tcp
sudo ufw delete allow 8080/tcp
With firewalld, you think about zones and services:
sudo firewall-cmd --zone=public --add-port=8080/tcp --permanent
sudo firewall-cmd --reload
sudo firewall-cmd --zone=public --remove-port=8080/tcp --permanent
sudo firewall-cmd --reload
The extra reload step ensures your permanent changes take effect, adding another command to remember. Beyond learning curves, your Linux distribution often makes the choice for you.
Distribution considerations
Your choice often gets made for you based on what distribution you're running.
Ubuntu, Debian, Linux Mint, and related distributions ship with UFW installed. It's the documented, supported firewall tool for these systems. You can install firewalld, but you're swimming against the current - documentation assumes UFW, support forums discuss UFW, and system tools expect UFW.
RHEL, CentOS, Fedora, Rocky Linux, and related distributions use firewalld as their standard firewall. It comes pre-configured and enabled. You can install UFW, but again, you're fighting the ecosystem.
This distribution divide isn't absolute - both tools work on any Linux system - but it affects your experience. Using the standard tool means better documentation, more community support, and fewer weird integration issues.
If you manage mixed environments with both Debian and Red Hat systems, you face a choice: learn both tools and use each distribution's standard, or standardize on one tool across everything.
Standardizing on UFW across all distributions means consistent firewall management but requires extra installation and configuration on RHEL systems. Standardizing on firewalld means installing it on Debian systems and working against Ubuntu's documentation.
Most organizations just use each distribution's standard. The tools are different enough that your documentation needs to account for distribution differences anyway, so using the standard tool simplifies other aspects of system management. With all these factors in mind, you're ready to decide which tool fits your specific situation.
Final thoughts
In the end, UFW and firewalld both do the same job: they help you manage a Linux firewall without writing raw iptables rules. UFW focuses on quick, simple rule management, while firewalld is better suited to more complex setups with multiple networks and trust levels.
For a typical single server running web apps, either tool is fine. Your best guide is your actual environment: how complex your network is, what features you really need, and which Linux distribution you use. Those practical details matter more than any theoretical feature list.