On RHEL 9 / Rocky 9 / Alma 9, firewalld is the default firewall front-end. Unlike UFW's flat rule list, firewalld groups rules into zones that you assign to interfaces — a much cleaner model once you stop fighting it.
Prerequisites
- Rocky 9 / Alma 9 / RHEL 9 with
sudo. firewalldinstalled (default on minimal install).
Step 1: Confirm firewalld is running
sudo systemctl status firewalld --no-pager
sudo firewall-cmd --state # expect: running
sudo firewall-cmd --get-zones # built-in zones
sudo firewall-cmd --get-default-zone
The default is usually public. For internet-facing servers, that is correct.
Step 2: List what is in a zone
sudo firewall-cmd --list-all
sudo firewall-cmd --zone=public --list-all
Out of the box public allows the ssh and dhcpv6-client services.
Step 3: Add services and ports
Two ways:
Named service (preferred — readable):
sudo firewall-cmd --permanent --zone=public --add-service=http
sudo firewall-cmd --permanent --zone=public --add-service=https
sudo firewall-cmd --reload
--permanent writes to disk; without it the change is runtime-only and lost on reload. --reload activates the on-disk config.
Explicit port (when there is no named service):
sudo firewall-cmd --permanent --zone=public --add-port=8080/tcp
sudo firewall-cmd --permanent --zone=public --add-port=30000-30100/tcp
sudo firewall-cmd --reload
Step 4: Source-based rules with rich rules
Allow Postgres from one app server only:
sudo firewall-cmd --permanent --zone=public --add-rich-rule='
rule family="ipv4"
source address="10.0.1.20/32"
port port="5432" protocol="tcp"
accept'
sudo firewall-cmd --reload
Drop ICMP from a misbehaving subnet:
sudo firewall-cmd --permanent --zone=public --add-rich-rule='
rule family="ipv4"
source address="203.0.113.0/24"
icmp-block name="echo-request"'
sudo firewall-cmd --reload
Step 5: Multiple zones for multi-NIC hosts
A box with two NICs (one public, one private) should pin each to its own zone:
sudo nmcli connection modify ens3 connection.zone public
sudo nmcli connection modify ens4 connection.zone internal
sudo nmcli connection up ens4
Then add management ports only to internal:
sudo firewall-cmd --permanent --zone=internal --add-service=ssh
sudo firewall-cmd --permanent --zone=internal --add-port=9090/tcp
sudo firewall-cmd --reload
Step 6: Remove and inspect
sudo firewall-cmd --permanent --zone=public --remove-service=http
sudo firewall-cmd --reload
# Inspect via direct iptables view
sudo iptables -L INPUT -n -v | head -20
sudo nft list ruleset | head -50
Verify
sudo firewall-cmd --list-all-zones
nmap -Pn -p 22,80,443 your.host.sa
Conclusion
Once you accept the "zone-per-interface" model, firewalld is the cleaner abstraction over nftables than UFW's flat list. Permanent vs runtime is the only footgun — always pair --permanent with --reload.
Next steps
- For RHEL family installs see Install Rocky Linux 9.
- Debug SELinux blocks with SELinux permissive mode.
- For the Ubuntu/Debian counterpart see UFW for specific ports.
Comments
0 total · 0 threads