Back to Linux guides

UFW vs firewalld: How to Pick the Right Linux Firewall Manager

Stanley Ulili
Updated on December 1, 2025

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
Output
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
Output
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
Output
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
Output
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
Output
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
Output
Available applications:
  Apache
  Apache Full
  Apache Secure
  OpenSSH
  Postfix
  Postfix SMTPS
  Postfix Submission

Each profile is a simple text file:

/etc/ufw/applications.d/apache2
[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
Output
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:

/usr/lib/firewalld/services/ssh.xml
<?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:

/etc/firewalld/services/myapp.xml
<?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:

/etc/ufw/before.rules
# 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:

/etc/default/ufw
DEFAULT_FORWARD_POLICY="ACCEPT"

And enable kernel IP forwarding:

/etc/sysctl.conf
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
Output
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.