firewalld is the default firewall manager on AlmaLinux, Rocky Linux, RHEL, CentOS Stream and Fedora. You control it with firewall-cmd. It organises rules into zones and services, and changes apply without dropping existing connections.

Status

sudo systemctl status firewalld
sudo firewall-cmd --state
sudo firewall-cmd --list-all

--list-all shows the default zone’s interfaces, allowed services and ports, and rich rules.

Runtime vs permanent

The most important concept:

  • Commands without --permanent change the running configuration — effective immediately, lost on reload or reboot.
  • Commands with --permanent change the saved configuration — effective after --reload.

Typical pattern:

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

Or test at runtime first, then save what’s running:

sudo firewall-cmd --add-port=8080/tcp
# test…
sudo firewall-cmd --runtime-to-permanent

Zones

A zone is a trust level with its own rules. Each network interface (or source address range) belongs to one zone.

firewall-cmd --get-zones
firewall-cmd --get-default-zone            # usually "public"
firewall-cmd --get-active-zones
sudo firewall-cmd --zone=public --list-all

Common zones: public (default, untrusted networks), internal, trusted (everything allowed), drop (drop everything incoming), block.

Bind a private interface to a more trusting zone:

sudo firewall-cmd --permanent --zone=internal --change-interface=eth1

Or assign a source range to a zone — e.g. let your VPN subnet reach everything:

sudo firewall-cmd --permanent --zone=trusted --add-source=10.8.0.0/24

Services and ports

firewall-cmd --get-services                 # predefined services
sudo firewall-cmd --permanent --add-service=http --add-service=https
sudo firewall-cmd --permanent --remove-service=cockpit
sudo firewall-cmd --permanent --add-port=8080/tcp
sudo firewall-cmd --permanent --add-port=27015-27030/udp
sudo firewall-cmd --reload

Services are XML definitions in /usr/lib/firewalld/services/. Create your own in /etc/firewalld/services/ for apps with several ports.

Changed the SSH port? Either add the new port, or edit a copy of the ssh service. Don’t remove ssh until the new port works. (SELinux also needs semanage port -a -t ssh_port_t -p tcp NEWPORT.)

Rich rules: IP-based restrictions

Allow MySQL only from the app server:

sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.0.0.6" port port="3306" protocol="tcp" accept'

Allow SSH only from your office network, and stop allowing it from everywhere:

sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="198.51.100.0/24" service name="ssh" accept'
sudo firewall-cmd --permanent --remove-service=ssh
sudo firewall-cmd --reload

Block an address:

sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.0.2.66" drop'

Rate limit:

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

List them: sudo firewall-cmd --list-rich-rules.

IP sets for large lists

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 --zone=drop --add-source=ipset:blocklist
sudo firewall-cmd --reload

Thousands of entries in an IP set are far more efficient than thousands of rich rules.

Port forwarding and masquerading

sudo firewall-cmd --permanent --add-masquerade
sudo firewall-cmd --permanent --add-forward-port=port=8080:proto=tcp:toport=80:toaddr=10.0.0.20
sudo firewall-cmd --reload

Masquerading is also what a VPN gateway needs to route client traffic to the internet.

Panic mode

sudo firewall-cmd --panic-on     # drop ALL traffic — including your SSH session
sudo firewall-cmd --panic-off

Only useful from the console during an active incident.

Logging denied packets

sudo firewall-cmd --set-log-denied=unicast
journalctl -k | grep -i "REJECT\|DROP"

firewalld and Docker

Docker creates its own docker zone and rules. Published container ports remain reachable regardless of your public zone settings — bind internal services to 127.0.0.1. See Docker networking.

Quick reference

Task Command
Show config firewall-cmd --list-all
Allow service --permanent --add-service=https
Allow port --permanent --add-port=8080/tcp
Allow port from IP --permanent --add-rich-rule='rule family="ipv4" source address="IP" port port="N" protocol="tcp" accept'
Apply permanent rules --reload
Save runtime rules --runtime-to-permanent
Trust a subnet --permanent --zone=trusted --add-source=CIDR

On Ubuntu and Debian, the equivalent tool is UFW. For the full concepts underneath, see nftables.

  • firewalld
  • Firewall
  • AlmaLinux