firewalld
firewalld is a dynamically managed firewall daemon for Linux operating systems that provides a zone-based interface to control network traffic, defining trust levels for connections and interfaces to enhance security without requiring service restarts for configuration changes.[1] It serves as a front-end for the Linux kernel's netfilter framework, utilizing backends such as nftables (default since version 0.6.0) or iptables to implement stateful packet filtering rules.[2]
Developed primarily by Thomas Woerner at Red Hat, firewalld is free and open-source software, licensed under GPLv2+. It was first released on January 3, 2011, and gained prominence as the default firewall in Fedora starting with version 18 in 2012, followed by Red Hat Enterprise Linux 7 in 2014.[3][4] Subsequent contributors include Jiri Popelka and Eric Garver, with ongoing maintenance under the firewalld project; as of November 2024, the latest stable version is 2.4.0.[3][5] The tool separates runtime (temporary) and permanent configurations, allowing immediate changes via the D-Bus interface while persisting rules across reboots only when explicitly saved.[6]
Key features include predefined zones like public, internal, and trusted to categorize network interfaces based on security requirements, where intra-zone traffic is permitted by default and inter-zone traffic is restricted unless explicitly allowed.[2] It supports service definitions for common protocols (e.g., HTTP, SSH), rich language rules for complex conditions like port ranges or IP sets, network address translation (NAT), ICMP type handling, and lockdown whitelisting to prevent unauthorized modifications.[2] Configuration is primarily handled through the command-line tool firewall-cmd, with graphical options like firewall-config (GTK3) and firewall-applet (Qt5) available for desktop environments.[1]
firewalld is widely adopted in enterprise distributions such as Red Hat Enterprise Linux, CentOS, Rocky Linux, Fedora, SUSE Linux Enterprise, and openSUSE, replacing direct iptables management for easier administration in dynamic environments like virtualized or cloud setups.[7] Its zone and policy model enables fine-grained control over input, output, forwarded, and NAT traffic, making it suitable for both servers and workstations requiring adaptive security policies.[2]
Overview
Introduction
firewalld is a dynamic daemon-based firewall management tool for Linux operating systems, acting as a front-end to the kernel's netfilter framework to control incoming and outgoing network traffic.[1] It replaces more static tools like iptables in many distributions by providing a higher-level interface that abstracts complex low-level rules into manageable configurations.[8]
The primary purpose of firewalld is to simplify network security management through zone-based policies, which allow administrators to assign trust levels to network interfaces or connections, and support runtime changes that apply immediately without requiring service restarts or disruptions to existing connections.[9] This design addresses the need for a user-friendly and dynamic firewall solution suitable for both desktop and server environments, where frequent policy adjustments are common without the overhead of reloading the entire firewall stack.[10]
firewalld, first released on January 3, 2011, was included as a proof-of-concept in Fedora 15 later that year, with motivations centered on enabling easier firewall configuration for non-experts and supporting dynamic updates to enhance usability in evolving network scenarios.[9] It became the default firewall in Fedora starting with version 18 in 2013 and in Red Hat Enterprise Linux (RHEL) with version 7 in 2014, where it has since been widely adopted for its integration with D-Bus for service management.[6][11] At its core, firewalld uses zones as an abstraction to assign network interfaces to predefined security profiles.[1]
History and Development
firewalld was initially developed by Thomas Woerner at Red Hat, with work beginning in 2010 and the project's first inclusion in a major distribution occurring in Fedora 15, released on May 24, 2011.[12][13] This marked the debut of firewalld as a dynamic firewall management tool, replacing simpler static configurations in upstream Fedora.[9]
Key milestones in firewalld's evolution include its integration as the default firewall in Red Hat Enterprise Linux 7, released on June 10, 2014, which broadened its adoption in enterprise environments. In 2013, the addition of rich rules introduced more flexible rule definitions, enabling complex configurations without direct backend manipulation.[14] The project underwent a significant backend transition starting with version 0.6.0 in July 2018, shifting from iptables to nftables for improved performance and modern kernel compatibility, with nftables becoming the default backend.[15] Full nftables support was solidified by 2020, aligning with updates in distributions like RHEL 8.[16]
Recent developments have focused on enhancing stability and compatibility, including version 2.0.0 released on June 23, 2023, which introduced features like zone priorities and nftables flowtable support. Subsequent contributors include Jiri Popelka and Eric Garver.[17] Improved IPv6 handling has been incrementally refined in subsequent releases. firewalld continues to be maintained primarily by Red Hat engineers, with substantial community contributions through its GitHub repository, ensuring ongoing updates and compatibility with evolving Linux ecosystems.[18] The latest stable release as of November 2025 is version 2.4.0, incorporating bug fixes and minor enhancements since the previous major update.[19]
Core Concepts
Zones
In firewalld, zones serve as the primary abstraction for defining network trust levels and applying firewall rules to incoming traffic based on the source or network interface. Each zone represents a predefined or custom set of rules that dictate how traffic is handled, with trust levels ranging from untrusted (restrictive) to fully trusted (permissive).[20][8]
Firewalld provides several predefined zones, each tailored to common network environments and ordered by increasing trust: drop (discards all incoming packets silently), block (rejects all incoming packets with an ICMP response), public (allows limited services for untrusted networks like Wi-Fi), external (similar to public but with IPv4 masquerading for external routers), dmz (permits limited access to public-facing servers while restricting internal reach), work (allows selected services in office settings), home (similar to work for residential networks), internal (more permissive for trusted corporate segments), and trusted (accepts all traffic). These zones inherently enable different sets of services, with higher-trust zones permitting broader access.[21][8]
Zones are assigned to network interfaces, such as binding the eth0 interface to the public zone for external connections, or to source addresses, like directing traffic from a specific IP range (e.g., 192.168.1.0/24) to the internal zone. This one-to-many relationship ensures that a single interface or source belongs to only one zone at a time, allowing firewalld to evaluate traffic contextually.[22][8]
The default zone, typically public upon installation, acts as a fallback for any interface, connection, or source not explicitly assigned to another zone, ensuring comprehensive coverage without gaps in policy application. Trust hierarchy dictates that unassigned traffic defaults to this lower-trust zone, promoting a deny-by-default posture unless elevated explicitly.[23][24]
Custom zones can be created to suit specific needs, such as defining a new zone for a virtual private network with tailored rules, and modified by adjusting elements like enabled services or ports while inheriting the zone model's structure. A key modifiable attribute is the target setting, which determines the fate of unmatched packets: ACCEPT (allows them through, as in trusted zones), DROP (discards silently, enhancing stealth), or REJECT (returns an error, as in block zones).[22][8]
Services and Ports
In firewalld, services provide a high-level abstraction for managing network access to common applications and protocols by encapsulating the necessary ports, protocols, and related firewall rules into predefined configurations.[25] A service is defined in an XML file that specifies elements such as ports, protocols, and optional firewall helpers or destinations, allowing administrators to enable or disable access to an entire service with a single command rather than configuring individual ports manually.[26] These service files are stored in directories like /usr/lib/firewalld/services/ for system-provided definitions or /etc/firewalld/services/ for custom ones, and they support inclusion of other services to build composite rules.[26]
Services relate to ports by explicitly listing them in the <port> element of the XML structure, where each entry includes a port number or range (e.g., "80" or "1000-2000") and an associated protocol such as TCP, UDP, SCTP, or DCCP.[26] For instance, the predefined "http" service opens TCP port 80 to allow web traffic, while the "dns" service permits both TCP and UDP on port 53.[26] Additionally, services can define raw protocols via the <protocol> element (e.g., IGMP) without specifying ports, or restrict access to specific IPv4 or IPv6 destinations using the <destination> element with address and mask attributes.[26] This design promotes reusability and reduces configuration errors, as enabling a service in a zone automatically applies all its associated ports and rules to incoming traffic on interfaces assigned to that zone.[25]
While services handle predefined or custom groupings, firewalld also supports direct management of individual ports for scenarios requiring fine-grained control without creating a full service definition.[27] Ports are added using commands like firewall-cmd --zone=public --add-port=8080/tcp, which opens TCP port 8080 in the specified zone for runtime changes, or with the --permanent flag for persistent rules reloaded on service restart.[27] Unlike services, direct port additions do not include protocols or helpers by default and must specify the protocol explicitly (e.g., /tcp or /udp), making them suitable for one-off openings such as custom application ports.[27] Both approaches integrate with zones, where rules are evaluated based on the trust level of the network interface, ensuring that services and ports only permit traffic from appropriate sources.[27]
For example, to enable the SSH service in the default zone, the command firewall-cmd --add-service=ssh would allow TCP port 22, whereas adding the port directly via firewall-cmd --add-port=22/[tcp](/page/TCP) achieves the same result but lacks the semantic clarity of referencing the service.[27] Custom services can be created by authoring an XML file, such as one for a hypothetical application on UDP port 1234:
<?xml version="1.0" encoding="utf-8"?>
<service version="1.0">
<short>MyApp</short>
<description>Custom application service</description>
<port port="1234" protocol="udp"/>
</service>
<?xml version="1.0" encoding="utf-8"?>
<service version="1.0">
<short>MyApp</short>
<description>Custom application service</description>
<port port="1234" protocol="udp"/>
</service>
This file, placed in the appropriate directory, can then be enabled like any predefined service.[26] Overall, using services over direct ports is recommended for maintainability, as updates to a service propagate changes across all zones where it is active, though direct ports offer flexibility for ephemeral or unique requirements.[27]
Architecture and Operation
Backends and Interfaces
Firewalld supports dual backend implementations for firewall management: the legacy iptables backend, which was the sole option prior to version 0.6.0, and the modern nftables backend, introduced as the default in version 0.6.0 released on July 12, 2018.[28][15] The iptables backend relies on separate tools like iptables, ip6tables, arptables, ebtables, and ipset for IPv4, IPv6, ARP, bridge, and set operations, respectively, while nftables unifies these into a single framework using the nft command for more efficient rule processing across protocols.[28] Firewalld automatically selects the backend based on kernel capabilities and the configuration setting, defaulting to nftables on supported systems to leverage its performance advantages, such as faster rule updates and built-in set support.[29][16]
At its core, firewalld employs an abstraction layer that translates user-defined zones, services, and rules into backend-specific constructs—such as chains in iptables or tables and chains in nftables—without any manual intervention from the administrator.[28] This layer ensures consistent operation across backends by mapping high-level firewalld primitives (e.g., ports, services, and rich rules) to equivalent low-level rules, while scoping firewalld's operations to dedicated tables, such as the firewalld table in the inet family, to minimize conflicts with external configurations.[28] For instance, when a zone is activated, firewalld generates and applies the corresponding backend rules dynamically, maintaining the firewall's stateful behavior regardless of whether iptables or nftables is in use.[30]
To maintain consistency, firewalld implements interface locking mechanisms that prevent direct modifications to the backend rules while the daemon is active; any external changes risk being overwritten or flushed upon reload or restart, as firewalld exclusively manages its scoped rules to avoid inconsistencies.[29][31] This design encourages all firewall adjustments through firewalld's interfaces, such as firewall-cmd, rather than direct backend tools.[8]
Switching between backends is configurable via the FirewallBackend option in /etc/firewalld/firewalld.conf, where administrators can specify nftables (default) or iptables to support legacy systems lacking nftables kernel modules.[29] After editing, restarting the firewalld service applies the change, with iptables mode providing compatibility for older environments but lacking nftables' unified protocol handling.[28] Direct and passthrough rules remain tied to traditional iptables backends even in nftables mode to preserve legacy compatibility.[29]
Runtime vs. Permanent Configuration
firewalld distinguishes between runtime and permanent configurations to enable flexible firewall management without immediate persistence risks. The runtime configuration represents the active firewall rules enforced in the kernel at any given moment, allowing administrators to test changes dynamically. These modifications take effect immediately but are volatile, meaning they are discarded upon service restart, system reboot, or reload operation.[32] In contrast, the permanent configuration is stored in XML files under /etc/firewalld and serves as the persistent baseline, automatically loaded into the runtime environment during boot or service initialization.[32]
Changes to the runtime configuration do not automatically propagate to the permanent settings, providing a safety mechanism for experimentation; to persist tested rules, an explicit migration from runtime to permanent is required. Permanent changes, however, remain inactive until explicitly applied via a reload, ensuring that ongoing operations are not unexpectedly altered. This separation supports iterative refinement, where runtime adjustments can be validated before committing to permanence across system cycles.[32][6]
The reload mechanism bridges these configurations by updating the runtime with permanent rules while preserving connection states to minimize disruption. Using the --reload option reloads the firewall service, replacing the current runtime with the permanent configuration and discarding any uncommitted runtime-only alterations, but it maintains active TCP sessions and other kernel state information. For scenarios requiring a full reset, such as resolving kernel module issues, the --complete-reload option discards all state, potentially terminating connections, though the standard reload avoids such interruptions. This state-preserving reload leverages the underlying backend's capabilities for seamless updates.[33][34]
Lockdown mode enhances control over configuration integrity by restricting runtime modifications through the D-Bus interface, preventing non-whitelisted applications or services from altering active rules. Enabled via configuration in firewalld.conf or runtime commands, it limits changes to trusted entities like specific SELinux contexts, user IDs, or commands, which is particularly valuable in scripted or automated environments where unintended overrides from local processes could compromise security. Whitelisting defaults include root (UID 0) and contexts for tools like NetworkManager, ensuring essential operations proceed while blocking unauthorized adjustments that might affect permanent setups indirectly.[35][29]
Features
Dynamic Management
firewalld operates as a daemon process, managed by the systemd service firewalld.service, which enables dynamic firewall management by applying rule changes at runtime without requiring a service restart or system reboot. This design separates runtime configurations, which take effect immediately and support temporary adjustments, from permanent configurations stored in /etc/firewalld/ that persist across restarts. The daemon uses a D-Bus interface to facilitate these updates, allowing tools like firewall-cmd to modify zones, services, and rules in real time, typically within seconds.[36][8]
The daemon monitors network events through integration with NetworkManager via D-Bus, automatically updating firewall rules in response to changes such as interface activation, deactivation, or renaming. For instance, when a network interface connects or a hotplugged device like a USB Ethernet adapter is detected, firewalld reassigns the interface to the appropriate zone based on the connection profile defined in NetworkManager, ensuring seamless adaptation without manual intervention. This hotplug support maintains consistent security policies during dynamic network topology shifts.[36][8]
firewalld includes built-in logging capabilities configurable in /etc/firewalld/firewalld.conf, where the LogDenied option can be set to values like all, unicast, broadcast, or multicast to record denied packets before rejection or dropping, aiding in security analysis. For troubleshooting dynamic operations, the daemon supports a debug mode activated by adding --debug (or a specific level) to the FIREWALLD_ARGS in the service configuration, which outputs detailed traces to the system journal; alternatively, enabling IndividualCalls in the config file provides granular error reporting for rule applications at the cost of slightly longer processing times. Rule changes can be audited using the system's auditd daemon by monitoring relevant commands or configuration file modifications, such as those to /etc/firewalld/, through custom audit rules like -a always,exit -F path=/usr/bin/firewall-cmd -F perm=x.[29][37]
In scenarios requiring immediate isolation, firewalld's panic mode temporarily blocks all incoming and outgoing traffic by dropping packets and allowing active connections to expire, invoked runtime via firewall-cmd --panic-on and disabled with --panic-off. While primarily manual, this mode can be triggered programmatically through the D-Bus interface for threat response, with status queried using --query-panic.[38]
Rich Rules and Policies
Rich rules in firewalld provide an advanced, element-based syntax for defining complex firewall behaviors that extend beyond simple service or port allowances, enabling conditions based on source, destination, protocols, and custom actions.[39] The syntax begins with rule followed by optional attributes like family="ipv4" or family="ipv6" to specify the address family, and priority="value" for ordering, where the default family applies to both IPv4 and IPv6 unless restricted.[39] Key elements include source [not] address="IP/mask" | mac="MAC" | ipset="name" to match originating traffic, destination [not] address="IP/mask" | ipset="name" for target matching, service name="name" to reference predefined services like "ssh", port port="port|range" protocol="tcp|udp" for specific ports, and protocol value="protocol" for layer-3 protocols such as ICMP.[39] Actions terminate the rule with options like accept to permit traffic, drop to silently discard packets, reject [type="notification"] to send an ICMP rejection (with types like "host-prohibited" for IPv4), or mark set="value[/mask]" to tag packets for routing decisions, all of which support rate limiting via limit value="rate/duration" (e.g., "5/m" for five per minute).[39] Logging can be integrated with log [prefix="text"] [level="emerg|alert|...|debug"] [limit value="rate/duration"] to record matches at specified levels (default: warning), or specialized options like nflog for netfilter logging or audit for auditd integration.[39]
For example, to allow TCP port 22 from a specific IPv4 subnet while logging attempts at info level with a rate limit, the rule is: rule family="ipv4" source address="192.168.1.0/24" port protocol="tcp" port="22" log prefix="SSH access" level="info" limit value="1/m" accept.[39] Masquerading is enabled via the masquerade element, which applies source NAT and implicitly activates IP forwarding for the zone, useful for outbound traffic hiding in scenarios like router configurations.[39] Forwarding is handled by forward-port port="port|range" protocol="tcp|udp" to-port="port" to-addr="IP", which redirects traffic to another address and port, also enabling forwarding if an external address is specified; for instance, rule family="ipv4" forward-port port="80" protocol="tcp" to-port="8080" to-addr="192.168.1.100" redirects HTTP to an internal server.[39]
Rich rules incorporate a priority system to control execution order, with values ranging from -32768 to 32767, where lower numbers indicate higher precedence and rules of equal priority have undefined order.[40] Rules with priority below 0 execute in a pre-chain before zone primitives, those above 0 in a post-chain after, and priority 0 sorts into log, deny, or allow chains based on the action, allowing precise sequencing such as logging before rejection.[40] An example sequence might use priority="-100" accept for broad allowance, followed by priority="-99" log prefix="Denied SSH" limit value="5/m" and priority="-98" source address="10.0.0.0/8" service name="ssh" reject to conditionally block and log SSH from a subnet.[40]
IP sets integrate seamlessly with rich rules by referencing predefined sets in source or destination elements, such as source ipset="blocked_ips" to apply rules against dynamic collections of addresses managed via firewall-cmd --new-ipset and --add-entry commands, enhancing efficiency for large-scale filtering without rule proliferation.[34]
Policies in firewalld, introduced in version 0.9.0 in 2020, extend control to inter-zone traffic by defining bidirectional rulesets that attach primitives like services, ports, and rich rules to specific ingress and egress zone pairs, unlike zones which primarily handle input filtering.[41] Configured in XML files under /etc/firewalld/policies/, each policy specifies a target attribute (e.g., "ACCEPT", "REJECT", "DROP", or "CONTINUE" as default) and uses <ingress-zone name="zone|ANY|HOST"/> for source zones and <egress-zone name="zone|ANY|HOST"/> for destinations, where "ANY" acts as a wildcard excluding "HOST" (which targets the local machine).[42] Policies activate when at least one non-symbolic ingress or egress zone is active with assigned interfaces or sources, enabling scenarios like restricting traffic from "public" to "internal" zones.[43] For instance, a policy file might contain <policy target="REJECT"><ingress-zone name="public"/><egress-zone name="internal"/><service name="http"/></policy> to block HTTP between those zones while rejecting others.[42] Internally, modern firewalld implements zones as policy sets, allowing policies to filter in input, output, and forwarding chains for comprehensive network or virtualization environments.[43]
Configuration
firewall-cmd serves as the primary command-line interface for managing the firewalld daemon, enabling administrators to configure runtime and permanent firewall settings through a straightforward set of options and subcommands.[38] It supports operations on zones, services, ports, and other elements, with flags like --zone to target specific zones and --permanent to apply changes persistently across reboots.[38] For instance, to add a service to a zone temporarily, one can use firewall-cmd --zone=public --add-service=http, which opens the necessary ports for the HTTP service in the public zone during the current runtime.[8] Similarly, adding a custom port involves commands like firewall-cmd --zone=public --add-port=8080/tcp --permanent, ensuring the TCP port 8080 remains open in the public zone even after system restarts, followed by firewall-cmd --reload to activate permanent changes without disrupting runtime.[8] The --list-all option provides a comprehensive view of a zone's configuration, displaying active services, ports, and interfaces, as in firewall-cmd --zone=public --list-all.[38]
Information-gathering commands facilitate inspection of firewalld's state and available resources. The --state option queries whether the daemon is running, returning an exit code of 0 if running, 251 if not running due to a problem, or 252 if not running.[38] Commands such as --get-zones list all defined zones, while --get-services enumerates predefined services like ssh or dns.[38] For panic mode status, --query-panic returns 0 if enabled, indicating that all incoming and outgoing packets are dropped.[38] These queries are essential for diagnostics, often used in scripts to verify configurations before applying changes.[8]
Advanced options extend functionality for specialized needs, though some are deprecated in favor of higher-level abstractions. The --direct flag allows passthrough to backend firewalls like nftables for low-level rule management, such as firewall-cmd --direct --add-rule ipv4 filter INPUT 0 -s 192.0.2.1 -j ACCEPT, but its use is discouraged for routine operations due to potential conflicts with firewalld's zone-based model.[8] Logging of denied packets can be configured via --set-log-denied, with levels including all (logs all denied packets), unicast (logs only unicast denials), broadcast, multicast, or off to disable logging entirely.[38] This is typically set system-wide, as in firewall-cmd --set-log-denied=all, to aid in auditing without overwhelming logs.[38]
For scripting and automation, firewall-cmd operates in non-interactive mode by default, suppressing unnecessary output with --quiet and relying on exit codes for success evaluation: 0 for success, 2 for invalid options, 11 for already-enabled elements, 12 for not-enabled, and 254 for unknown errors.[38] Temporary rules can be added with --timeout, such as firewall-cmd --zone=public --add-port=8080/[tcp](/page/TCP) --timeout=30s, limiting the change to 30 seconds for testing.[38] Multiple operations can be chained using the --add- sequence options, where the command succeeds (exit 0) if at least one subcommand does, supporting reliable integration in shell scripts or tools like Ansible.[38]
Graphical and Programmatic Interfaces
firewalld offers graphical user interfaces (GUIs) for visual configuration, primarily through the firewall-config tool, which integrates with desktop environments such as GNOME and KDE. This tool provides an intuitive interface for managing firewall settings without requiring command-line interaction, displaying active zone bindings for interfaces and sources on the left panel while allowing users to select and modify zones via dedicated tabs.[44] Additionally, the cockpit-firewall plugin extends web-based management capabilities within the Cockpit server administration platform, enabling remote access to firewalld configurations through a browser.[45]
Key features in these GUIs include visual zone assignment, where users can drag-and-drop or select interfaces and sources to assign them to specific zones, and service toggles that allow enabling or disabling predefined services like SSH or HTTP with simple checkboxes.[44][46] The firewall-config tool supports runtime and permanent modes, with icons indicating permanent configurations, and includes editors for rich rules to define complex conditions such as source IP restrictions or rate limiting, enhancing usability for advanced scenarios.[39] Cockpit's interface similarly focuses on service management for the default zone, listing available services and permitting additions or removals with immediate effect.[45] These GUIs leverage the underlying D-Bus API and command-line tools for backend operations, ensuring consistency with firewalld's core functionality.[6]
For programmatic access, firewalld exposes a D-Bus API under the interface org.fedoraproject.FirewallD1, accessible at the object path /org/fedoraproject/FirewallD1, which supports operations such as reloading configurations, enabling or disabling panic mode, setting the default zone, and querying lists of services or ICMP types.[47] This API facilitates integration in scripting languages, particularly Python, through the official python3-firewall bindings provided in the firewalld package, allowing developers to perform runtime queries like retrieving active zones or adding ports programmatically.[48] For example, a Python script can connect to the D-Bus bus and call methods such as getDefaultZone() to fetch the current default zone setting.[47]
Third-party tools extend programmatic control, notably the ansible.posix.firewalld module in Ansible, which orchestrates firewalld configurations across systems by adding or removing services, ports, and rich rules in either runtime or permanent modes.[49] This module requires the python3-firewall bindings and supports idempotent operations, such as enabling the HTTPS service permanently with a task like ansible.posix.firewalld: service=https state=enabled permanent=true.[49] For runtime queries, it can gather information on zones and rules, enabling automated deployment in environments like cloud infrastructures.[50]
Advanced Usage
Forward and Output Filtering
Firewalld handles forwarded traffic through policy objects, which enable filtering between zones or interfaces, addressing scenarios such as network address translation (NAT) and routing. These policies are stateful and unidirectional, applied between an ingress zone (source) and an egress zone (destination), with configurable priorities to determine rule precedence relative to zone rules. For instance, in NAT setups like masquerading in an external zone, administrators can create a policy with ingress set to the public zone and egress to an internal zone, adding masquerade rules to rewrite source addresses for outbound traffic from internal networks.[41][8]
Intra-zone forwarding, which allows traffic between interfaces or sources within the same zone, can be enabled using the firewall-cmd --add-forward option on a specific zone, such as the internal zone for local network routing. Rich rules further enhance forward filtering by supporting complex conditions, like forwarding specific ports or protocols between zones; for example, a rich rule in a policy might forward TCP port 80 from the public ingress zone to a dmz egress zone while logging the action. For non-zone-based forwards, policies provide the primary mechanism, though deprecated direct rules via firewall-cmd --direct --add-rule can insert low-level nftables or iptables commands into the FORWARD chain, such as accepting traffic on a bridge interface.[38][51]
The output chain in firewalld manages traffic generated by the local host, distinct from input and forward chains, and is configured primarily through policies where the ingress zone is set to HOST to target locally originated packets. This allows rules for scenarios like blocking outbound connections to specific IP addresses, such as denying UDP traffic to a known malicious range from the host itself. Integration with ipset enables dynamic blacklisting in output rules; for example, creating an ipset named "blacklist" with hash:ip type and adding entries via firewall-cmd --add-entry, then referencing it in a rich rule like rule family="ipv4" destination address="[blacklist](/page/The_Blacklist)" drop applied to an output policy.[41][38]
For IPv6 forwarding, firewalld supports address-based filtering through policies that can target specific IPv6 addresses, including global unicast addresses, ensuring selective allowance of traffic based on IPv6-specific criteria. NDP handling is facilitated by built-in policies like "allow-host-ipv6", which permit essential ICMPv6 types such as neighbor solicitation, neighbor advertisement, router advertisement, and redirect to maintain IPv6 connectivity in forwarded paths. Rich rules are required for IPv6 port forwarding, as the simpler --add-forward-port is IPv4-only.[41]
Integration and Customization
Firewalld supports extensibility through dedicated directories in the /etc/firewalld path, where administrators can define custom XML configuration files for services, zones, and other components to tailor the firewall behavior without modifying upstream defaults. These custom files, placed in subdirectories such as /etc/firewalld/services or /etc/firewalld/zones, take precedence over the read-only defaults in /usr/lib/firewalld, enabling seamless integration of organization-specific rules or third-party service definitions. While firewalld does not natively provide script hooks for events like pre- or post-zone changes, external monitoring of D-Bus signals or systemd events can trigger custom scripts for advanced automation.[52][53][54]
A key integration point is with NetworkManager, which automatically assigns firewalld zones to network connections upon activation, applying context-aware rules based on connection profiles such as wired, Wi-Fi, or VPN. This ensures that trusted networks like home or office connections map to permissive zones (e.g., "home" or "internal"), while untrusted ones default to stricter settings like "public," enhancing security without manual intervention on connection changes.[55][56]
Firewalld operates as a systemd service (firewalld.service), allowing dependencies to be declared in unit files for coordinated startup, such as requiring network-online.target to ensure rules apply after interface configuration. This integration facilitates scenarios where other services depend on firewalld's readiness, like database servers needing open ports post-firewall initialization, while avoiding common dependency loops through proper After= directives.[57]
For container and virtual machine environments, firewalld accommodates traffic from tools like Docker and libvirt by supporting masquerading rules on bridged networks, which enable outbound connectivity for isolated workloads. Administrators can add masquerade to a relevant zone (e.g., via firewall-cmd --zone=public --add-masquerade) to handle NAT for Docker's default bridge or libvirt's virtual networks, while the dedicated "libvirt" zone automatically manages VM forwarding with built-in trust levels for internal traffic. This setup ensures secure isolation without exposing host interfaces unnecessarily.[58][59][60]
Limitations and Alternatives
Known Limitations
Firewalld provides basic stateful inspection through its reliance on the Linux kernel's connection tracking (conntrack) mechanism, which allows implicit handling of return traffic for established connections without explicit rules. However, it lacks native support for advanced stateful features beyond these fundamentals, requiring administrators to define manual rules for complex connection states, and it does not include built-in deep packet inspection (DPI) capabilities for analyzing application-layer content.[8]
The tool's backend dependencies introduce constraints, as the iptables mode has been deprecated since version 1.0.0 in 2021, with announcements indicating its removal in future releases to enforce migration to nftables for improved performance and compatibility. This deprecation, coupled with the exclusive use of either iptables or nftables to avoid conflicts, necessitates reconfiguration for systems still using the legacy backend, particularly as nftables becomes the sole supported option; as of November 2025, the iptables backend remains available but deprecated without removal.[61][29]
Scalability issues arise with high rule counts, where configurations involving numerous rules or large ipsets can prolong reload operations due to the overhead of regenerating the underlying nftables or iptables rulesets. While ipsets offer a mitigation strategy by grouping addresses to reduce rule complexity, this optimization is not applied automatically and requires manual implementation.[62]
Firewalld's IPv6 support has shown inconsistencies, particularly for advanced features like policy routing and rpfilter options, with partial implementation until improvements in version 2.2.0 released in July 2024, which enhanced IPv6 rpfilter modes (including loose, loose-forward, and strict-forward variants) and policy object handling for better dual-stack compatibility; further IPv6 fixes, such as allowing MLD packets and validating ICMPv6 codes, were added in subsequent releases up to version 2.4.0 in November 2025. Fedora Workstation plans to default to IPv6_rpfilter=loose starting with Fedora 42 in 2025 to improve multi-homed connectivity.[63][64]
Comparisons to Other Firewalls
Firewalld provides a higher-level abstraction over the Netfilter framework, utilizing either iptables or nftables as its backend, which introduces ease of use through zones and services but at the cost of added overhead compared to direct manipulation of iptables or nftables.[65] Direct use of iptables or nftables offers finer-grained control, such as creating custom chains or complex rule sets without the abstraction layer, making it preferable for scenarios requiring low-level packet filtering precision, though it demands greater expertise and lacks firewalld's dynamic runtime updates.[66] In contrast, firewalld's design prioritizes simplicity and integration in dynamic environments, avoiding the need to flush and reload entire rule sets during changes, which can disrupt traffic in pure iptables setups.[67]
Compared to Uncomplicated Firewall (UFW), the default on Ubuntu systems, firewalld targets more advanced and enterprise use cases with features like network zones for trust-level management and runtime policy adjustments, while UFW emphasizes simplicity for beginners through straightforward command syntax and lacks native support for zones or dynamic interfaces.[68] UFW's ease of adoption suits basic server or desktop configurations, but its limited extensibility for complex policies makes firewalld a better fit for environments integrated with systemd and NetworkManager, where automatic zone assignment enhances security without manual intervention.[69]
Shorewall, a high-level Netfilter configurator, offers extensive customization for multi-interface setups and advanced routing, but its configuration files and steeper learning curve contrast with firewalld's more accessible interface and seamless systemd integration for service management.[70] While Shorewall excels in granular control over traffic shaping and per-IP policies, firewalld provides a more streamlined approach for standard enterprise deployments, reducing administrative overhead in systemd-based distributions.[71]
Migration from iptables to firewalld is facilitated by tools like the offline mode of firewall-cmd, which allows loading and converting existing iptables rulesets into firewalld configurations without running the daemon, a capability available since firewalld's maturation in 2015 distributions like RHEL 7.[72] This process typically involves exporting iptables rules via iptables-save, then using firewall-cmd --offline to build equivalent zones and services, ensuring minimal disruption during transitions.[73]
Adoption
Distribution Support
firewalld serves as the default firewall management tool in several major Linux distributions, particularly those in the Red Hat ecosystem. In Red Hat Enterprise Linux (RHEL) versions 7 and later, firewalld is installed, enabled, and active by default, providing dynamic firewall management with nftables as the backend since RHEL 8.[74][30] Similarly, CentOS 7 and newer, along with its successors like Rocky Linux and AlmaLinux starting from version 7, include firewalld as the standard firewall solution, installed by default and configured to start on boot.[75][76][7]
Fedora has adopted firewalld as its default firewall since version 18 (released in 2013), with all subsequent editions, including the latest Fedora 43 (released October 2025), installing, configuring, and activating it automatically during setup, except in cloud images where minimal configuration may be needed.[6][1] The package in Fedora 43 is named firewalld-2.3.1-5.fc43, reflecting ongoing updates to the tool.[77]
Among other distributions, openSUSE and SUSE Linux Enterprise (version 15 and later) use firewalld as the default firewall, integrated with zones for network trust levels and manageable via firewall-cmd or graphical tools like Cockpit.[1][78][79] In Debian 10 (Buster) and newer, firewalld is available as an optional package but not enabled by default, with nftables serving as the primary backend. Ubuntu distributions offer firewalld through the repositories for installation, though Uncomplicated Firewall (ufw) remains the preferred default for its simplicity.[76][80]
To enable firewalld on supported distributions where it is installed but not active, administrators can use the systemd command systemctl enable firewalld to set it for boot and systemctl start firewalld to run it immediately, followed by verification with systemctl status firewalld.[81][76][74]
Usage Statistics and Trends
Firewalld holds a substantial presence in enterprise Linux environments, primarily due to its status as the default firewall management tool in Red Hat Enterprise Linux (RHEL), which commands approximately 43% of the enterprise Linux server market share as of 2025.[82] This adoption has grown steadily, reflecting broader Linux server dominance in enterprise settings, where RHEL's integration of firewalld facilitates zone-based management for secure network configurations, including in RHEL 10 released in May 2025. In contrast to earlier years, firewalld's usage in smaller setups, including home and small-business Linux installations, shows combined activity with tools like UFW at 88.4% according to a 2024 Linux Foundation survey, underscoring its versatility across scales.[82]
Recent trends indicate a strong shift toward the nftables backend within firewalld, which has become the default in major distributions by 2025. For instance, RHEL 9.6 and 10, along with SUSE Linux Enterprise, now prioritize nftables over the legacy iptables backend, enabling more efficient packet processing and compatibility with modern kernel features.[83][84] This migration reflects declining reliance on iptables, with nftables adoption nearing ubiquity in new deployments to support advanced filtering without service disruptions.[16]
In real-world applications, firewalld is commonly deployed in cloud infrastructures such as AWS EC2 instances running RHEL or Fedora AMIs, where its zones simplify inbound traffic control alongside AWS Security Groups—for example, defining public zones for web services while restricting private interfaces.[85] On servers, it protects web applications like Apache and Nginx by allowing runtime additions of service rules, such as opening HTTP ports in the default zone without restarting the daemon.[86] For desktops, firewalld serves as the standard in Fedora workstations, enabling users to manage accessibility via simple commands that block unsolicited incoming connections while permitting essential services like SSH.[6]
Community engagement with firewalld remains robust, evidenced by its GitHub repository garnering over 950 stars and maintaining around 250 open issues as of late 2025, with ongoing discussions centered on backend optimizations and integration improvements.[63]