How to Install Firewalld on CentOS Stream 10 and 9

Install and configure Firewalld on CentOS Stream 10 and 9. Manage zones, services, ports, rich rules, and troubleshoot common issues.

Last updatedAuthorJoshua JamesRead time9 minGuide typeCentOS Stream

CentOS Stream normally uses firewalld for host firewall management, but minimal images, custom rebuilds, and older server templates can still leave firewall-cmd missing or the daemon stopped. Install firewalld on CentOS Stream when you want the standard zone-based workflow for protecting SSH, web ports, Cockpit, and other services without writing raw nftables rules.

These steps apply to CentOS Stream 10 and CentOS Stream 9. Stream 10 currently carries firewalld 2.4.x, while Stream 9 carries 1.3.x; the core firewall-cmd workflow works on both releases.

Install Firewalld on CentOS Stream

Refresh package metadata and apply pending updates before changing firewall packages. CentOS Stream uses DNF 4 on both current Stream releases.

sudo dnf upgrade --refresh -y

These commands use sudo because package installation, service control, and firewall changes require root privileges. If your account does not have sudo access, switch to a root shell before running the same commands.

Install the package from the CentOS Stream base repositories. On standard server images, DNF may report that firewalld is already installed; the same command is still safe because DNF exits without reinstalling it.

sudo dnf install firewalld -y
Package firewalld-2.4.0-1.el10.noarch is already installed.
Dependencies resolved.
Nothing to do.
Complete!

Enable the systemd service so the firewall starts at boot, and start it immediately in the current session.

sudo systemctl enable --now firewalld

Verify Firewalld Installation on CentOS Stream

Confirm the package version, service state, boot enablement, and daemon state with a compact set of checks.

rpm -q firewalld
sudo firewall-cmd --version
systemctl is-active firewalld
systemctl is-enabled firewalld
sudo firewall-cmd --state
firewalld-2.4.0-1.el10.noarch
2.4.0
active
enabled
running

CentOS Stream 9 reports a 1.3.x firewalld package instead. Treat exact RPM release numbers as moving package metadata and verify your host with rpm -q firewalld when the precise build matters.

Understand CentOS Stream Firewalld Defaults

Firewalld is the default firewall manager on normal CentOS Stream server installs. It manages the kernel packet filter through a higher-level interface, usually backed by nftables, while the iptables-nft compatibility tools remain available for older scripts. Avoid running separate firewalld and nftables management paths on the same host unless you deliberately maintain both rule paths, because independent managers can make the active ruleset harder to reason about.

The upstream firewall-cmd manual describes the runtime and permanent configuration model, and Red Hat’s firewall and packet-filter documentation explains the same firewalld and nftables relationship for RHEL-family systems. On CentOS Stream, the default zone is normally public.

sudo firewall-cmd --get-default-zone
public

Inspect the public zone to see which services are allowed before you add or remove rules.

sudo firewall-cmd --zone=public --list-all
public (default, active)
  target: default
  ingress-priority: 0
  egress-priority: 0
  icmp-block-inversion: no
  interfaces: ens33
  sources:
  services: cockpit dhcpv6-client ssh
  ports:
  protocols:
  forward: yes
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:

CentOS Stream 9 shows the same default services but omits the ingress-priority and egress-priority lines. The important checks are the active zone, the interface bound to it, and the services or ports already allowed.

Manage Runtime and Permanent Firewalld Rules

The firewall-cmd tool separates temporary runtime changes from saved permanent configuration. Runtime-only changes are useful for testing, but they disappear after reloads and reboots unless you save them.

firewall-cmd [options] <command>
  • --zone=public: Targets a named zone instead of relying on the default zone.
  • --permanent: Saves the change to disk, but the runtime firewall does not see it until reload.
  • --reload: Replaces the runtime configuration with the saved permanent configuration.

A temporary rule is useful when you want to test access before committing it.

sudo firewall-cmd --zone=public --add-service=http

Save the same rule permanently, then reload firewalld so the active ruleset matches the saved configuration.

sudo firewall-cmd --permanent --zone=public --add-service=http
sudo firewall-cmd --reload

If you already tested several runtime changes and want to keep all of them, copy the active runtime configuration into the permanent configuration.

sudo firewall-cmd --runtime-to-permanent

Open Services and Ports with Firewalld

Use service names when firewalld already knows the application. Service definitions are easier to audit than raw port numbers because the rule describes the workload, not only the transport.

Keep the active SSH path allowed before changing firewall rules over a remote session. CentOS Stream’s public zone normally allows ssh, but removing that service, changing the default zone, or enabling panic mode can disconnect you unless you have console access or another tested management path.

Allow HTTP and HTTPS Services

Open web traffic for an Apache HTTPD server on CentOS Stream or another local web service.

sudo firewall-cmd --permanent --zone=public --add-service=http
sudo firewall-cmd --permanent --zone=public --add-service=https
sudo firewall-cmd --reload

Use yes-or-no service queries for the final proof.

sudo firewall-cmd --zone=public --query-service=http
sudo firewall-cmd --zone=public --query-service=https
yes
yes

Remove an Allowed Service

Remove a service when you no longer want that inbound traffic exposed. The Cockpit web console is a common example on headless servers that use SSH instead of a browser-based admin UI.

sudo firewall-cmd --permanent --zone=public --remove-service=cockpit
sudo firewall-cmd --reload

Confirm the service is no longer allowed in the active zone.

sudo firewall-cmd --zone=public --query-service=cockpit
no

Open and Verify a TCP Port

Use a direct port rule when no built-in service definition matches the application. This example opens TCP port 3000 for a local application server.

sudo firewall-cmd --permanent --zone=public --add-port=3000/tcp
sudo firewall-cmd --reload

Query the exact port and protocol instead of relying on a long zone listing.

sudo firewall-cmd --zone=public --query-port=3000/tcp
yes

Close the port when the application moves behind a reverse proxy, changes ports, or no longer needs inbound access.

sudo firewall-cmd --permanent --zone=public --remove-port=3000/tcp
sudo firewall-cmd --reload
sudo firewall-cmd --zone=public --query-port=3000/tcp
no

Work with Firewalld Zones on CentOS Stream

Zones group interfaces, sources, services, ports, and rich rules by trust level. A laptop, private backend network, and internet-facing server should not all share the same firewall assumptions.

List Active Zones

Check which zones currently have interfaces or sources attached.

sudo firewall-cmd --get-active-zones
public (default)
  interfaces: ens33

Change the Default Zone

Set a different default zone only when the host’s normal network trust level changes. Workstations on a trusted LAN may use home, while internet-facing servers usually stay on public or move to a stricter custom policy.

sudo firewall-cmd --set-default-zone=home

The default-zone change is both runtime and permanent. Recheck active zones after changing it because interfaces already bound to explicit zones may not move.

CentOS Stream Firewalld Zone Reference

ZoneTrust LevelDefault BehaviorBest Fit
dropZeroSilently drops incoming packetsHostile networks or temporary isolation
blockZeroRejects incoming packets with a prohibited responseUntrusted networks where rejection feedback is useful
publicLowAllows selected services onlyCloud instances and internet-facing servers
externalLowDesigned for outward-facing gatewaysRouter or NAT systems
dmzLowAllows a small set of public-facing servicesExposed web or mail relay hosts
workMediumTrusts managed workplace networksOffice desktops and managed LANs
homeMediumAllows common home-network discovery servicesPersonal workstations on trusted networks
internalHighTrusts internal business networksBackend servers and management networks
trustedFullAccepts all trafficLoopback, VPN, or fully trusted links only
sudo firewall-cmd --get-zones
block dmz drop external home internal public trusted work

Add Advanced Firewalld Rules

Advanced rules are useful when a service definition or single port is not enough. Keep them narrow, verify each rule after reload, and prefer documentation comments in custom service files so future administrators understand the intent.

Create a Custom Firewalld Service

Custom service files under /etc/firewalld/services/ let you name an application once and reuse it across zones. This example defines a service named myapp for TCP port 8080.

sudo tee /etc/firewalld/services/myapp.xml > /dev/null <<'EOF'
<?xml version="1.0" encoding="utf-8"?>
<service>
  <short>myapp</short>
  <description>Custom application listening on TCP 8080</description>
  <port protocol="tcp" port="8080"/>
</service>
EOF
sudo firewall-cmd --check-config
success

Reload firewalld, add the service permanently to the public zone, then confirm the service is active.

sudo firewall-cmd --reload
sudo firewall-cmd --permanent --zone=public --add-service=myapp
sudo firewall-cmd --reload
sudo firewall-cmd --zone=public --query-service=myapp
yes

Rate-Limit SSH with a Rich Rule

Firewalld rich rules support rate limits through the limit value="rate/duration" syntax documented in the firewalld rich language manual. Rate-limiting SSH needs extra care because a normal public zone already allows SSH through the built-in ssh service.

Do not remove the broad ssh service from a remote-only host unless you have console access or another working login path. A rich rule only controls SSH meaningfully after the regular ssh service rule is removed or narrowed.

sudo firewall-cmd --permanent --zone=public --add-rich-rule='rule service name="ssh" limit value="10/m" accept'
sudo firewall-cmd --permanent --zone=public --query-rich-rule='rule service name="ssh" limit value="10/m" accept'
yes

After the saved rich rule returns yes, remove the broader built-in SSH service rule and reload firewalld.

sudo firewall-cmd --permanent --zone=public --remove-service=ssh
sudo firewall-cmd --reload
sudo firewall-cmd --zone=public --list-rich-rules
rule service name="ssh" accept limit value="10/m"

This rule allows new SSH connections up to the configured limit. For repeated authentication attacks, log-based tools such as Fail2Ban usually provide better control because they ban sources after failed login patterns instead of only rate-limiting connection attempts.

Block a Specific IP Address

Use a source-address rich rule when you need to block a known abusive host. The example address comes from the documentation-only TEST-NET range.

sudo firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="192.0.2.50" log prefix="blocked-ip: " level="info" drop'
sudo firewall-cmd --reload
sudo firewall-cmd --zone=public --list-rich-rules
rule family="ipv4" source address="192.0.2.50" log prefix="blocked-ip: " level="info" drop

Block Network Ranges with an Ipset

Ipsets keep large address lists cleaner than long chains of individual rich rules. Create the ipset, add networks to it, attach the ipset to a rich rule, and reload.

sudo firewall-cmd --permanent --new-ipset=blocklist --type=hash:net
sudo firewall-cmd --permanent --ipset=blocklist --add-entry=203.0.113.0/24
sudo firewall-cmd --permanent --ipset=blocklist --add-entry=198.51.100.0/24
sudo firewall-cmd --permanent --zone=public --add-rich-rule='rule source ipset="blocklist" drop'
sudo firewall-cmd --reload
sudo firewall-cmd --zone=public --list-rich-rules
rule source ipset="blocklist" drop

Add another network later without rewriting the rich rule.

sudo firewall-cmd --permanent --ipset=blocklist --add-entry=192.0.2.0/24
sudo firewall-cmd --reload

Enable Masquerading for NAT

Use masquerading only when the CentOS Stream host routes traffic for another network. A normal single-interface server does not need NAT masquerading just to expose local services.

sudo firewall-cmd --permanent --zone=external --add-masquerade
sudo firewall-cmd --reload
sudo firewall-cmd --zone=external --query-masquerade
yes

Forward Traffic to Another Local Port

A forward-port rule redirects traffic that reaches one local port to another local port. This example accepts TCP traffic on port 80 and forwards it to a service listening on port 8080 on the same host.

sudo firewall-cmd --permanent --zone=public --add-forward-port=port=80:proto=tcp:toport=8080
sudo firewall-cmd --reload
sudo firewall-cmd --zone=public --query-forward-port=port=80:proto=tcp:toport=8080
yes

Troubleshoot Firewalld on CentOS Stream

Most firewalld failures fall into a few repeatable buckets: the package is missing, the command needs root authorization, the application is not listening on the expected interface, or a runtime rule was never saved permanently.

firewall-cmd Command Not Found

A minimal system can lack firewalld entirely. The shell error looks like this:

sudo: firewall-cmd: command not found

Install the firewalld package, start the daemon, and verify the command path.

sudo dnf install firewalld -y
sudo systemctl enable --now firewalld
command -v firewall-cmd
/usr/bin/firewall-cmd

Authorization Failed Without sudo

Over SSH, a normal user may see a polkit authorization error when running privileged firewalld queries without sudo.

Authorization failed.
    Make sure polkit agent is running or run the application as superuser.

Repeat the command with sudo. For example, version and state checks work reliably this way:

sudo firewall-cmd --version
sudo firewall-cmd --state
2.4.0
running

Service Works Locally But Not Remotely

When an application answers on localhost but not from another machine, first confirm that the application listens beyond 127.0.0.1.

sudo ss -tlnp | grep ':8080'
LISTEN 0 4096 0.0.0.0:8080 0.0.0.0:* users:(("myapp",pid=1234,fd=7))

If the listener is bound to 127.0.0.1, fix the application binding first. If it listens on 0.0.0.0 or the server’s network address, verify the firewalld port rule.

sudo firewall-cmd --zone=public --query-port=8080/tcp
yes

If the query returns no, add the port permanently and reload.

sudo firewall-cmd --permanent --zone=public --add-port=8080/tcp
sudo firewall-cmd --reload

Rules Disappear After Reload or Reboot

Rules added without --permanent live only in the runtime configuration. Compare runtime and permanent output to spot the difference.

sudo firewall-cmd --zone=public --list-ports
sudo firewall-cmd --permanent --zone=public --list-ports

If the first command lists a port that the second command omits, save the current runtime configuration or add the rule again with --permanent.

sudo firewall-cmd --runtime-to-permanent

Firewalld Fails to Start After XML Changes

Broken custom zone or service XML can stop firewalld from loading cleanly. Check the permanent configuration first.

sudo firewall-cmd --check-config
success

If the check reports an XML or semantic error, inspect the journal for the file name and line context.

sudo journalctl -xeu firewalld --no-pager

Move the damaged custom file aside, then restart firewalld. Replace custom.xml with the file named in the error.

sudo mv /etc/firewalld/zones/custom.xml /etc/firewalld/zones/custom.xml.bak
sudo systemctl restart firewalld
sudo firewall-cmd --state
running

Panic Mode Blocks All Traffic

Panic mode drops all network traffic immediately. Check it from the local console if remote access stopped unexpectedly after firewall work.

sudo firewall-cmd --query-panic
yes

Turn panic mode off, then confirm firewalld is running again.

sudo firewall-cmd --panic-off
sudo firewall-cmd --state
running

Firewalld Command Quick Reference

These core tasks cover the commands most administrators reuse after the first setup.

TaskCommandWhat It Does
Check daemon statesudo firewall-cmd --statePrints whether firewalld is running
Show default zonesudo firewall-cmd --get-default-zoneShows where new unassigned interfaces land
List active zonessudo firewall-cmd --get-active-zonesShows zones with attached interfaces or sources
Inspect public zonesudo firewall-cmd --zone=public --list-allShows services, ports, sources, and rich rules
Add HTTP permanentlysudo firewall-cmd --permanent --zone=public --add-service=http && sudo firewall-cmd --reloadAllows HTTP and applies the saved change
Open TCP port 8080sudo firewall-cmd --permanent --zone=public --add-port=8080/tcp && sudo firewall-cmd --reloadAllows one custom TCP port
Verify a portsudo firewall-cmd --zone=public --query-port=8080/tcpReturns yes or no
Save runtime rulessudo firewall-cmd --runtime-to-permanentCopies active runtime rules into permanent storage
Check XML configsudo firewall-cmd --check-configValidates saved custom service and zone files
Check panic modesudo firewall-cmd --query-panicShows whether all traffic is being dropped

Update Firewalld on CentOS Stream

Firewalld updates arrive through the CentOS Stream repositories with the rest of the operating system. A normal system update is enough for routine maintenance, but you can target firewalld directly when you want to refresh only that package and review the transaction first.

sudo dnf upgrade --refresh firewalld

Recheck the installed package and daemon state after an update, especially on remote systems where firewall availability matters.

rpm -q firewalld
sudo firewall-cmd --state
firewalld-2.4.0-1.el10.noarch
running

Remove Firewalld from CentOS Stream

Removing firewalld leaves the host without its standard firewall manager. Keep another verified firewall path, console access, or an out-of-band recovery method before you disable it on a remote server.

Stop and Disable Firewalld

Stop the daemon and remove the boot-time enablement symlink.

sudo systemctl disable --now firewalld

Verify both runtime and boot state with stable one-word checks.

systemctl is-active firewalld || true
systemctl is-enabled firewalld || true
inactive
disabled

Remove the Firewalld Package

Remove the package with DNF. Leaving off -y gives you a chance to review the dependency list before confirming the transaction.

sudo dnf remove firewalld

DNF can also offer to remove unused helper packages such as firewalld-filesystem, python3-firewall, python3-nftables, ipset, or iptables-nft. Review that list before confirming if other local firewall workflows depend on those packages.

Verify the package is no longer installed.

rpm -q firewalld
package firewalld is not installed

Remove Leftover Firewalld Configuration

Package removal can leave custom zone, service, and ipset files under /etc/firewalld/. Preview the remaining files before deleting them.

sudo test -d /etc/firewalld && sudo find /etc/firewalld -mindepth 1 -maxdepth 2 -print || echo "no-firewalld-config-directory"

The next command permanently deletes firewalld configuration, including custom services, zones, ipsets, and rich rules. Keep a backup if you might reinstall firewalld later.

sudo rm -rf -- /etc/firewalld
sudo test ! -e /etc/firewalld && echo "firewalld-config-removed"
firewalld-config-removed

Conclusion

Firewalld is now installed, enabled, and ready to manage CentOS Stream network access through zones, services, ports, and richer policy rules. If the host serves websites, pair these rules with Apache HTTPD on CentOS Stream; for remote administration changes, review the ssh command in Linux before tightening access.

Share this guide

Help another Linux user troubleshoot faster

Share this guide with someone troubleshooting Linux systems or saving it for later.

Follow LinuxCapable

Want more LinuxCapable guides in Google?

Add LinuxCapable as a preferred source so Google can show more of our fresh Linux tutorials in Top Stories and From your sources when relevant.

Add LinuxCapable as a preferred source on Google
Search LinuxCapable

Need another guide?

Search LinuxCapable for package installs, commands, troubleshooting, and follow-up guides related to what you just read.

Found this guide useful?

Support LinuxCapable to keep tutorials free and up to date.

Buy me a coffeeBuy me a coffee
Before commenting, please review our Comments Policy.
Formatting tips for your comment

You can use basic HTML to format your comment. Useful tags currently allowed in published comments:

You type Result
<code>command</code> command
<strong>bold</strong> bold
<em>italic</em> italic
<blockquote>quote</blockquote> quote block

Got a Question or Feedback?

We read and reply to every comment - let us know how we can help or improve this guide.

Verify before posting: