How to Install Firewalld on CentOS Stream (10, 9)

When managing a CentOS Stream server or workstation, controlling network traffic is fundamental to securing your system against unauthorized access. Firewalld provides a dynamic firewall manager that organizes network rules into zones based on trust levels, allowing you to adapt security policies without disrupting active connections.

This guide demonstrates how to install and configure Firewalld on CentOS Stream, covering zone management, service and port rules, advanced rich rule configurations, and troubleshooting techniques that help maintain secure network boundaries.

These instructions apply to CentOS Stream 10 and CentOS Stream 9. Commands work identically on both releases unless noted otherwise. CentOS Stream 8 reached end-of-life in May 2024 and is no longer supported.

What Is Firewalld?

Firewalld acts as a management layer between your applications and the underlying nftables (or iptables) packet filtering system. Rather than writing complex filtering rules directly, you interact with Firewalld through the firewall-cmd utility, which translates your requests into the appropriate backend rules. This abstraction simplifies firewall administration while preserving the full power of Linux packet filtering.

The daemon maintains two configurations simultaneously: runtime (active but temporary) and permanent (saved to disk). This separation lets you test changes immediately and commit them only after verification, reducing the risk of locking yourself out of remote systems. Firewalld delivers several key advantages for CentOS Stream environments:

  • Zone-Based Architecture: Network interfaces map to zones representing trust levels, from “drop” (zero trust) to “trusted” (full access), letting you apply different policies to different network segments.
  • Runtime Changes Without Restart: Modify rules instantly without cycling the service or dropping established connections, essential for production servers where uptime matters.
  • Predefined Services: Common applications like SSH, HTTP, and HTTPS have built-in service definitions, eliminating the need to memorize port numbers.
  • Rich Rule Language: Create complex conditional rules that combine source addresses, logging, rate limiting, and packet marking for advanced traffic control.
  • IPv4 and IPv6 Unified Management: Handle both protocol families through the same interface without maintaining separate rule sets.

On CentOS Stream servers, Firewalld integrates with Cockpit for web-based management and coordinates with SELinux policies to provide defense in depth. Whether you’re securing a database server, web application host, or KDE Plasma desktop, Firewalld gives you the flexibility to define precise network boundaries.

Check If Firewalld Is Installed

Before proceeding with installation, determine whether Firewalld already exists on your system. Server installations of CentOS Stream typically include Firewalld, while minimal or container images often omit it to reduce footprint. Check for an existing installation by querying the version:

sudo firewall-cmd --version

If Firewalld is installed and the daemon is accessible, the command returns the version number:

2.4.0

On CentOS Stream 9, you’ll see version 1.3.x instead. If the command fails with “command not found” or a connection error, Firewalld needs installation using the steps below.

Install Firewalld on CentOS Stream

Install Firewalld from the base CentOS Stream repositories using DNF:

sudo dnf install firewalld -y

DNF resolves dependencies automatically, pulling in nftables, Python bindings, and supporting libraries. The installation completes in seconds on most systems.

Enable and Start Firewalld

After installation, configure Firewalld to launch at boot and activate it immediately. The --now flag combines both operations:

sudo systemctl enable --now firewalld

This command creates the systemd symlink for automatic startup and brings the daemon online in a single step.

Verify Firewalld Status

Confirm the service is running correctly before configuring rules:

sudo systemctl status firewalld --no-pager

Healthy output shows “active (running)” with the daemon process details:

● firewalld.service - firewalld - dynamic firewall daemon
     Loaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled; preset: enabled)
     Active: active (running) since Mon 2026-01-26 05:15:22 UTC; 1min ago
       Docs: man:firewalld(1)
   Main PID: 2847 (firewalld)
      Tasks: 2 (limit: 23146)
     Memory: 28.4M
        CPU: 425ms
     CGroup: /system.slice/firewalld.service
             └─2847 /usr/bin/python3 -s /usr/sbin/firewalld --nofork --nopid

For a quick state check, use the dedicated Firewalld command:

sudo firewall-cmd --state
running

Understanding Firewalld Command Structure

Before configuring rules, understanding the command syntax helps you work efficiently and avoid mistakes. Every Firewalld command follows a consistent pattern that becomes intuitive with practice.

Firewalld requires root privileges on CentOS Stream. All examples use sudo; omit it only if you’re already operating in a root shell. If you need to set up a sudo-enabled account, see how to create a sudo user on CentOS Stream.

Command Syntax Overview

The firewall-cmd utility accepts options that modify behavior and commands that perform actions:

firewall-cmd [options] <command>

Common options include:

  • --zone=name: Target a specific zone instead of the default
  • --permanent: Write changes to disk for persistence across reboots
  • --reload: Apply permanent changes to the runtime configuration

Runtime vs Permanent Configuration

Firewalld maintains separate runtime and permanent configurations. Commands without --permanent affect only the active session and revert after a reload or reboot. This design lets you test rules safely:

Test a rule temporarily:

sudo firewall-cmd --add-service=http

Make a rule permanent:

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

Save all runtime rules to permanent storage:

sudo firewall-cmd --runtime-to-permanent

Essential Firewalld Commands

The following commands cover everyday firewall administration tasks on CentOS Stream systems. Each example uses concrete values rather than placeholders to demonstrate real-world usage.

View the Default Zone

Identify which zone handles traffic for new interfaces:

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

CentOS Stream uses “public” as the default zone, which permits SSH, DHCPv6 client, and Cockpit web console by default.

List Active Zones

See which zones are currently in use and their associated interfaces:

sudo firewall-cmd --get-active-zones
public
  interfaces: eth0

Display Zone Configuration

Inspect all rules configured in the public zone:

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

This output reveals the services currently allowed through the zone’s firewall rules.

Add a Service to a Zone

Allow HTTP traffic through the public zone permanently. If you’re setting up an Apache web server or a LEMP stack on CentOS Stream, you’ll need both HTTP and HTTPS:

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

Verify the services were added:

sudo firewall-cmd --zone=public --list-services
cockpit dhcpv6-client http https ssh

Remove a Service from a Zone

Block a service by removing it from the zone’s allowed list. For example, to remove the Cockpit service from the public zone:

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

Open a Specific Port

When no predefined service exists for your application, open ports directly. For example, to allow TCP traffic on port 3000 for a Node.js application:

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

View open ports in the zone:

sudo firewall-cmd --zone=public --list-ports
3000/tcp

Close a Port

Remove a port rule when no longer needed:

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

Change the Default Zone

Set a different zone as the default for new interfaces. For a workstation on a trusted network, the home zone offers more permissive defaults:

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

For servers exposed to the internet, keep “public” or use “dmz” for maximum restriction.

Firewall Zones Reference

Firewalld ships with nine predefined zones covering common trust scenarios. Understanding each zone’s purpose helps you select the appropriate security level for different network segments.

ZoneTrust LevelDefault BehaviorBest For
dropZeroSilently discards all incoming packets; outbound allowedHostile networks, isolation scenarios
blockZeroRejects incoming with ICMP prohibited messagesUntrusted networks requiring RFC compliance
publicLowOnly selected services (SSH, Cockpit, DHCPv6)Cloud instances, internet-facing servers
externalLowMasquerading enabled for NAT routingGateway systems, router configurations
dmzLowMinimal services; isolated from internal networkPublic-facing web servers, mail relays
workMediumTrusts coworkers; standard office servicesCorporate networks with managed systems
homeMediumRelaxed rules; discovery protocols enabledHome networks with personal devices
internalHighSimilar to home; for business internal networksBackend servers, management networks
trustedFullAccepts all traffic without filteringVPN tunnels, loopback, fully trusted links

List all available zones with:

sudo firewall-cmd --get-zones
block dmz drop external home internal public trusted work

Advanced Firewalld Configuration

Beyond basic service and port management, Firewalld supports advanced scenarios including custom service definitions, IP blocking, and network address translation.

Create a Custom Service Definition

When managing applications that don’t have predefined service definitions, create your own. Service XML files stored in /etc/firewalld/services/ persist across updates:

sudo tee /etc/firewalld/services/myapp.xml <<'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 --reload
sudo firewall-cmd --permanent --zone=public --add-service=myapp
sudo firewall-cmd --reload

The custom service now appears alongside built-in services and can be added to any zone.

Block Traffic from Specific IP Addresses

Use rich rules to block suspicious hosts while logging the attempts. This approach works well with log monitoring tools:

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

Check the system journal to confirm blocked packets are being logged:

sudo journalctl -k | grep "blocked-ip:" | tail -5

Ban Network Ranges with Ipsets

For blocking large numbers of addresses efficiently, ipsets provide better performance than individual rich rules:

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

Add or remove entries from the ipset as threats evolve:

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

Enable Masquerading for NAT

When your CentOS Stream system acts as a gateway between networks, enable masquerading to translate internal addresses:

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

Verify masquerading is active:

sudo firewall-cmd --zone=external --query-masquerade
yes

Configure Port Forwarding

Redirect incoming traffic from one port to another, useful for running services on non-standard ports while accepting connections on standard ones:

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

This forwards incoming TCP connections on port 80 to port 8080 on the same host.

Troubleshooting Firewalld

When firewall issues arise, systematic troubleshooting helps identify whether the problem lies with Firewalld configuration, the application, or network infrastructure.

Service Accessible Locally But Not Remotely

When an application works on localhost but fails from other hosts, first verify the service is listening on all interfaces, not just 127.0.0.1:

sudo ss -tlnp | grep :8080

If the service binds only to localhost, reconfigure the application. If it listens on 0.0.0.0, check that the port or service is allowed through Firewalld:

sudo firewall-cmd --get-active-zones
sudo firewall-cmd --zone=public --list-all

Confirm your interface belongs to the expected zone and the service or port appears in the allowed list.

Rules Disappear After Reboot

If rules vanish after restarting, they were added without --permanent. Compare runtime and permanent configurations:

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

Any rules present in the first output but missing from the second are runtime-only. Save current runtime rules with:

sudo firewall-cmd --runtime-to-permanent

Firewalld Fails to Start

When Firewalld won’t start after adding custom rules, syntax errors in zone or service XML files are often responsible. Check the journal for specific errors:

sudo journalctl -xeu firewalld --no-pager | tail -30

If a custom zone file is corrupted, temporarily move it aside and restart:

sudo mv /etc/firewalld/zones/public.xml /etc/firewalld/zones/public.xml.bak
sudo systemctl restart firewalld

This restores the default zone configuration, letting you rebuild rules incrementally.

Interface Assigned to Wrong Zone

NetworkManager controls zone assignments for connections it manages. To permanently assign an interface to a specific zone:

sudo nmcli connection show

Note the connection name, then set its zone:

sudo nmcli connection modify "Wired connection 1" connection.zone internal
sudo nmcli connection up "Wired connection 1"

Recovering from Panic Mode

Panic mode drops all network traffic immediately. If you accidentally enabled it and lost remote access, connect via console and disable it:

sudo firewall-cmd --query-panic

If the output is “yes”, restore connectivity:

sudo firewall-cmd --panic-off

Panic mode persists only until the next reload or reboot, so restarting the system also clears it.

Quick Reference: Common Commands

Use this table for quick lookups during day-to-day firewall administration:

TaskCommand
Check daemon statussudo firewall-cmd --state
List all zonessudo firewall-cmd --get-zones
Get default zonesudo firewall-cmd --get-default-zone
List active zonessudo firewall-cmd --get-active-zones
View zone configurationsudo firewall-cmd --zone=public --list-all
Add service (permanent)sudo firewall-cmd --permanent --add-service=http && sudo firewall-cmd --reload
Remove servicesudo firewall-cmd --permanent --remove-service=http && sudo firewall-cmd --reload
Open portsudo firewall-cmd --permanent --add-port=8080/tcp && sudo firewall-cmd --reload
Close portsudo firewall-cmd --permanent --remove-port=8080/tcp && sudo firewall-cmd --reload
Change default zonesudo firewall-cmd --set-default-zone=home
Save runtime to permanentsudo firewall-cmd --runtime-to-permanent
Block an IP addresssudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="1.2.3.4" reject'
Enable masqueradingsudo firewall-cmd --permanent --zone=external --add-masquerade && sudo firewall-cmd --reload
Assign interface to zonesudo nmcli connection modify "Connection Name" connection.zone home
Emergency block allsudo firewall-cmd --panic-on
Restore from panicsudo firewall-cmd --panic-off

Remove Firewalld from CentOS Stream

If you prefer an alternative firewall solution or need to troubleshoot conflicts, you can remove Firewalld entirely.

Stop and Disable the Service

First, stop the running daemon and prevent it from starting at boot:

sudo systemctl disable --now firewalld

Verify the service stopped:

sudo systemctl status firewalld --no-pager
○ firewalld.service - firewalld - dynamic firewall daemon
     Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; preset: enabled)
     Active: inactive (dead)

Remove the Package

Removing Firewalld leaves your system without firewall protection. If you’re connected via SSH, ensure you have alternative access or another firewall configured before proceeding.

sudo dnf remove firewalld -y

Verify removal:

rpm -q firewalld
package firewalld is not installed

Remove Configuration Files

Custom zone configurations and service definitions remain in /etc/firewalld/ after package removal. To complete the cleanup:

This permanently deletes all custom zones, services, and ipsets. Only proceed if you don’t need to restore the configuration later.

sudo rm -rf /etc/firewalld/

Common Questions

What is the difference between Firewalld versions on CentOS Stream 9 and Stream 10?

CentOS Stream 9 ships Firewalld 1.3.x while Stream 10 includes version 2.4.x. The newer version offers improved policy support, enhanced nftables integration, and better handling of complex rule sets. Fundamental commands remain compatible across both versions, so guides written for one version generally work on the other.

Can I use iptables instead of Firewalld on CentOS Stream?

CentOS Stream uses nftables as the underlying packet filtering framework, not legacy iptables. The iptables-nft compatibility layer translates iptables syntax to nftables rules, so existing scripts still work. You can disable Firewalld and manage nftables directly with the nft command, or use iptables-nft for familiar syntax. However, Firewalld provides easier zone-based management for most use cases.

Conclusion

Firewalld delivers flexible, zone-based network protection for CentOS Stream servers and workstations. Through the firewall-cmd interface, you can manage services, ports, and complex traffic policies without writing raw nftables rules. The separation of runtime and permanent configurations enables safe testing before committing changes, while rich rules and ipsets provide advanced capabilities for blocking threats and managing complex network topologies.

Leave a Comment

Let us know you are human: