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
sudobecause 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
| Zone | Trust Level | Default Behavior | Best Fit |
|---|---|---|---|
| drop | Zero | Silently drops incoming packets | Hostile networks or temporary isolation |
| block | Zero | Rejects incoming packets with a prohibited response | Untrusted networks where rejection feedback is useful |
| public | Low | Allows selected services only | Cloud instances and internet-facing servers |
| external | Low | Designed for outward-facing gateways | Router or NAT systems |
| dmz | Low | Allows a small set of public-facing services | Exposed web or mail relay hosts |
| work | Medium | Trusts managed workplace networks | Office desktops and managed LANs |
| home | Medium | Allows common home-network discovery services | Personal workstations on trusted networks |
| internal | High | Trusts internal business networks | Backend servers and management networks |
| trusted | Full | Accepts all traffic | Loopback, 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
sshservice from a remote-only host unless you have console access or another working login path. A rich rule only controls SSH meaningfully after the regularsshservice 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.
| Task | Command | What It Does |
|---|---|---|
| Check daemon state | sudo firewall-cmd --state | Prints whether firewalld is running |
| Show default zone | sudo firewall-cmd --get-default-zone | Shows where new unassigned interfaces land |
| List active zones | sudo firewall-cmd --get-active-zones | Shows zones with attached interfaces or sources |
| Inspect public zone | sudo firewall-cmd --zone=public --list-all | Shows services, ports, sources, and rich rules |
| Add HTTP permanently | sudo firewall-cmd --permanent --zone=public --add-service=http && sudo firewall-cmd --reload | Allows HTTP and applies the saved change |
| Open TCP port 8080 | sudo firewall-cmd --permanent --zone=public --add-port=8080/tcp && sudo firewall-cmd --reload | Allows one custom TCP port |
| Verify a port | sudo firewall-cmd --zone=public --query-port=8080/tcp | Returns yes or no |
| Save runtime rules | sudo firewall-cmd --runtime-to-permanent | Copies active runtime rules into permanent storage |
| Check XML config | sudo firewall-cmd --check-config | Validates saved custom service and zone files |
| Check panic mode | sudo firewall-cmd --query-panic | Shows 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.


Formatting tips for your comment
You can use basic HTML to format your comment. Useful tags currently allowed in published comments:
<code>command</code>command<strong>bold</strong><em>italic</em><blockquote>quote</blockquote>