Open-source project
firewalld/firewalld avatar
firewalld/firewalld

firewalld turns firewall rules into zones you can change at runtime

Stateful zone based firewall daemon with D-Bus interface

1,049 stars309 forksPythonGPL-2.0

At a glance

What is it?
firewalld is a Python daemon with a D-Bus interface that manages a dynamic Linux firewall through zones, separating runtime state from permanent configuration. It suits administrators and applications that need to change firewall rules without a reload, and it is built on nftables with iptables and ebtables support.
Who is it for?
Adopt firewalld if you want firewall changes to take effect immediately without a reload, if you need zones to express trust levels per interface or network, or if an application on the host needs to add rules through a stable D-Bus interface instead of editing iptables rules directly.
Can I use it commercially?
Yes, with conditions. GPL-2.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository last received commits 15 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Zones carry the trust decision, not a rule list

firewalld provides a dynamically managed firewall with support for network or firewall zones to define the trust level of network connections or interfaces. That sentence contains the whole design.

The traditional way to configure a Linux firewall is a ruleset: an ordered list of accept, drop and reject rules that you match packets against. firewalld replaces that with an indirection. You attach an interface or a network to a zone, and the zone carries a policy: what is trusted, what services are allowed, what is forwarded. A packet arriving on an interface belongs to a zone, and the zone decides.

The point is that a change of trust level becomes a change of label rather than a rewrite of a rule order. Moving an interface from one zone to another is a single operation, and it is atomic in a way that inserting a rule in the middle of a chain is not.

The daemon also supports IPv4 and IPv6 firewall settings, ethernet bridges, and a separation of runtime and permanent configuration options. That last one matters in practice. A runtime change applies immediately and disappears on reload; a permanent change is written to disk and survives. The distinction is the reason the tool can be driven by an installer that wants a temporary test, or by a desktop that adds a rule for a file transfer and expects it to be gone afterwards.

On top of that, firewalld provides an interface for services or applications to add iptables and ebtables rules directly, so an application that needs a hole can ask for one rather than editing the ruleset behind the daemon's back.

D-Bus is the control surface, which is why other software can use it

The project describes itself as a firewall daemon with a D-Bus interface, and that interface is the architectural decision worth understanding.

A D-Bus service is a local, per-user or per-system bus with a defined interface contract. A program that speaks it can ask the daemon to add a port, list zones, or reload, without knowing how the rules are implemented underneath. The result is that firewalld, NetworkManager, libvirt, podman and desktop applications can each ask for firewall changes and get consistent behaviour, instead of each of them maintaining its own chain.

The repository ships the policy file that makes this possible. The README says a dbus policy can be obtained from the source code tree at config/FirewallD.conf, and it is installed to the system bus directory:

sh
cp config/FirewallD.conf /usr/share/dbus-1/system.d/FirewallD.conf

That single file is the whole authorisation model for third-party clients, which is worth keeping in mind when you install it, because it is what grants permission for another program on the system to change your firewall.

The runtime dependencies confirm the shape of the system:

code
  linux >= 5.3
  python >= 3.8
  python3-dbus
  python3-gobject
  python3-nftables >= 0.9.4

python3-nftables at 0.9.4 or newer is the hard requirement of the modern backend, python3-gobject is what gives the daemon its GLib main loop, and python3-dbus is the bus binding. The README also notes plainly that python2 is not supported, which is a leftover of the era when this daemon was first written and still matters if you are deploying to an old distribution.

The optional dependencies are ebtables, ipset, iptables, polkit and python3-capng, and they are what broaden the tool beyond the nftables core.

The test suite runs in network namespaces, and the integration tests do not

The README's build and test section is unusually explicit about what will and will not affect your machine, which is the right way to write it for a firewall.

The build is the standard autoconf and automake sequence. You clone the repository, run ./autogen.sh and then ./configure, and make builds the documentation and updates the po files. A specific interpreter can be selected with the PYTHON variable, which is also what the test suite uses:

sh
./configure PYTHON=/path/to/python3

The unit test suite runs inside network namespaces and does not interfere with the host's running firewalld. It can be run in parallel by passing flags to autotest:

sh
make check TESTSUITEFLAGS="-j4"

And the suite is keyword driven, so you can run a subset that exercises one area:

sh
make check TESTSUITEFLAGS="-k rich -j4"

The keyword list itself is discoverable with make -C src/tests check TESTSUITEFLAGS="-l", and the README shows a longer pipeline that strips the numbering and sorts the keywords.

Then there is the part that deserves the warning. There are integration tests, currently including NetworkManager, and the README says these may be destructive to the host, and to run them in a disposable VM or container. There is also a check-container target that runs the suite inside various podman or docker containers, which is described as useful for coverage of multiple distributions, and which also runs the destructive tests.

That split is the right engineering: the namespace-isolated unit tests are safe to run on a developer machine on every commit, while the integration tests that talk to a real network manager need a disposable environment, and the container target gives you one.

The container image needs a D-Bus policy to talk to the host

firewalld builds an OCI container image as part of the dist target, distributed alongside the normal release tarball, and the README documents both a standalone mode and a host integration mode.

In standalone mode the containerised firewalld will not integrate with the host, and the examples make that concrete. The image is pulled from quay.io:

sh
podman pull quay.io/firewalld/firewalld:<ver>

where the version is optional and the latest is used if omitted. It is started privileged with the host network:

sh
podman run -d --network host --privileged \
              --name my-firewalld firewalld

Because the configuration lives inside the container, the README suggests users may want to commit the image occasionally with podman commit to preserve it. The CLI is then driven through podman exec against the running container, which is firewall-cmd with the container name.

The host integration mode is where the D-Bus policy comes in. The same image can be used to integrate with the host's running NetworkManager, podman or libvirt, which requires the host to have a dbus policy for firewalld, copied from the source tree as shown earlier. With the policy in place, the container is started with the system bus socket mounted and an explicit command:

sh
podman run -d -v /run/dbus/system_bus_socket:/run/dbus/system_bus_socket \
              --network host --privileged \
              --name my-firewalld firewalld \
              firewalld --nofork --nopid

The README notes the only additions are the volume mount and the explicit command. A third variant mounts /etc/firewalld from the host as well, which is described as the same approach used to store the configuration files on the host.

The practical note for anyone evaluating this: a containerised firewall is either isolated from the host, in which case it is not the host's firewall, or it is attached to the host bus and network, in which case it has a great deal of authority and the D-Bus policy is the thing to get right.

Building the RPM and the container image shows the packaging paths

Two packaging routes are documented, and the repository layout supports both.

For Fedora and RHEL based distributions there is a spec file in the source repo named firewalld.spec, which the README says should be usable for Fedora versions 16 and newer and RHEL 7 and newer. That is a wide support window for a distribution firewall daemon, and it is a reasonable indicator of the project's staying power.

The Dockerfile at the repository root is the container build, and it is a good illustration of how the project is assembled. It starts from quay.io/centos/centos:stream9, installs the build and runtime dependencies including automake, autoconf, intltool, docbook-style-xsl, python3-nftables, python3-gobject-base, libxslt, glib2-devel and python3-dbus, plus the test suite dependencies diffutils, procps, iproute, dbus-daemon and python3-devel. It then runs the ordinary autogen, configure, make and make install sequence, removing the build dependencies afterwards to keep the image small.

Two details in the Dockerfile are worth noting. The configure call passes --prefix=/usr and PYTHON=/usr/libexec/platform-python, which is the interpreter path on that platform. And the container ships the D-Bus policy by copying config/FirewallD.conf into /usr/share/dbus-1/system.d/ as part of the image build, with docker_start.sh in the root directory as the entrypoint.

The rest of the repository is the autoconf scaffolding: Makefile.am, configure.ac, autogen.sh, an m4/ directory for macros, po/ for translations, doc/ for documentation, config/ for the D-Bus policy and other configuration, contrib/ for contributed pieces, shell-completion/ for the command line completions, src/ for the code, and a Dockerfile. The top level also has a .flake8 for linting and a pyproject.toml that configures black with target versions from py37 to py310 and an include list covering the .py files plus the .in templates that generate the command line tools, which are firewall-cmd, firewall-config, firewall-offline-cmd, firewall-applet and firewalld itself.

GPL-2.0, Weblate translations, and a busy release line

The licence is GPL-2.0, with the COPYING file in the repository as the authoritative text, and this is a licensing statement rather than legal advice.

The release record shows steady work. v2.5.2 was released on 2026-09-17, v2.5.1 on 2026-08-07 and v2.3.4 on 2026-07-09. The repository is not archived and the last push was on 2026-10-08, so development is current.

The versioning is worth a note. The gap from 2.3.4 to 2.5.1 is a jump of two minor versions in a single month, which suggests a maintenance branch and a feature branch running in parallel, and that v2.3.4 is a line continued for distributions that need a conservative point release. If you are on a distribution that ships firewalld, you may be on the older branch and not see the newer features.

Localisation runs through GNU gettext, with the po/ directory in the repository and translations done on Fedora's Weblate instance, from which they are periodically merged back into the main repository. That arrangement is a good fit for a project whose users are distributed across many distributions: one translation platform, merged on a schedule, rather than per-distribution translation forks.

The CI story is visible in the badges at the top of the README, with separate workflows for the test suite, an integration test suite, and source code and build checks. Three separate pipelines rather than one is a signal that the destructive integration tests are kept away from the fast path, which matches the README's own guidance about running them in a disposable environment.

Editorial conclusion

Adopt firewalld if you want firewall changes to take effect immediately without a reload, if you need zones to express trust levels per interface or network, or if an application on the host needs to add rules through a stable D-Bus interface instead of editing iptables rules directly. Do not adopt it if your host already manages rules through a different layer that would fight it, because two managers writing the same ruleset is the classic way to lose a firewall configuration. Before you deploy, check the runtime dependencies including python3-nftables 0.9.4 or newer and a kernel of 5.3 or newer, and decide whether you want the container image, which the README says will not integrate with the host unless you add a D-Bus policy.

Frequently asked questions

What are the runtime dependencies for firewalld?

The README lists linux >= 5.3, python >= 3.8, python3-dbus, python3-gobject and python3-nftables >= 0.9.4, and notes that python2 is not supported. Optional dependencies that enhance functionality but are not required are ebtables, ipset, iptables, polkit and python3-capng.

How do I build firewalld from source?

Clone the repository, run ./autogen.sh and then ./configure, and use make to create the documentation and update the po files. A specific interpreter can be chosen with ./configure PYTHON=/path/to/python3, and make check runs the test suite.

Can I run the firewalld tests on my own machine safely?

The unit test suite runs inside network namespaces and does not interfere with the host's running firewalld, and it can be parallelised with make check TESTSUITEFLAGS="-j4" or filtered by keyword with -k. The integration tests, which currently include NetworkManager, may be destructive to the host, so the README says to run them in a disposable VM or container, and make check-container does that in podman or docker.

How do I run firewalld in a container and integrate it with the host?

Pull the image with podman pull quay.io/firewalld/firewalld:<ver> and run it with --network host --privileged. To integrate with the host's NetworkManager, podman or libvirt, copy the dbus policy from the source tree with cp config/FirewallD.conf /usr/share/dbus-1/system.d/FirewallD.conf and mount the system bus socket when starting the container. Without the policy the containerised firewalld does not integrate with the host.

What is the difference between runtime and permanent configuration in firewalld?

The README describes firewalld as providing a separation of runtime and permanent configuration options. A runtime change applies immediately and is lost on reload, while a permanent change is written to disk and survives, and the project also offers firewall-offline-cmd among its command line tools.

Official sources

  1. firewalld/firewalld on GitHub
  2. Issues
  3. License: GPL-2.0
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/firewalld-firewalld.svg)](https://hysenlabs.com/projects/firewalld-firewalld)

Was this useful?