What it is¶
firewalld is the dynamic firewall manager on RHEL, CentOS, Fedora, and their relatives. Instead of a flat list of rules, it groups network interfaces and source addresses into zones, each with its own trust level and its own set of allowed services and ports. It drives nftables underneath on current releases (iptables on older ones) — see the iptables and nftables guides for the engine layer, and Netfilter for the hook points both use.
Project site: firewalld.org.
Default zones¶
| Zone | Default behaviour for incoming traffic |
|---|---|
trusted |
Allow everything |
home |
Reject unless related to outgoing traffic or one of: ssh, mdns, ipp-client, samba-client, dhcpv6-client |
internal |
Same as home to start with |
work |
Reject unless related to outgoing traffic or one of: ssh, ipp-client, dhcpv6-client |
public |
Reject unless related to outgoing traffic or ssh/dhcpv6-client. Default zone for new interfaces |
external |
Reject unless related or ssh. IPv4 traffic forwarded out through this zone is masqueraded |
dmz |
Reject unless related or ssh |
block |
Reject everything not related to outgoing traffic (with an ICMP error) |
drop |
Silently drop everything not related to outgoing traffic |
Zone management¶
sudo firewall-cmd --get-active-zones # zones with interfaces/sources bound
sudo firewall-cmd --get-default-zone
sudo firewall-cmd --zone=public --list-all # everything configured in a zone
sudo firewall-cmd --permanent --zone=internal --change-interface=eth1
Assigning an interface via the legacy network-scripts file (RHEL 7 style, NM_CONTROLLED=no) means adding a ZONE= line:
DEVICE="eth0"
BOOTPROTO="static"
ONBOOT="yes"
IPADDR="192.168.0.253"
NETMASK="255.255.255.0"
GATEWAY="192.168.0.254"
ZONE="external"
On NetworkManager-managed interfaces set it there instead, or firewalld and NM will disagree: nmcli connection modify "<conn>" connection.zone external (see nmcli).
Services and ports¶
# Open/close a predefined service
sudo firewall-cmd --permanent --zone=public --add-service=https
sudo firewall-cmd --permanent --zone=public --remove-service=dhcpv6-client
# Open/close an arbitrary port
sudo firewall-cmd --permanent --zone=public --add-port=8080/tcp
sudo firewall-cmd --permanent --zone=public --remove-port=8080/tcp
sudo firewall-cmd --reload # apply permanent config to the running firewall
--permanent writes config without changing the running state, and running-state changes (no --permanent) vanish on reload. The usual workflow is permanent change + --reload. --complete-reload also drops existing connection state, so it interrupts live sessions — use it only when you must.
Port forwarding¶
sudo firewall-cmd --permanent --zone=external \
--add-forward-port=port=8443:proto=tcp:toport=443:toaddr=192.168.1.20
sudo firewall-cmd --permanent --zone=external \
--remove-forward-port=port=8443:proto=tcp:toport=443:toaddr=192.168.1.20
Forwarding to another host needs masquerading on the zone that faces the destination (below) and IP forwarding enabled.
Rich rules¶
Rich rules express conditions the plain service/port model cannot: source addresses, logging, rejects, rate limits.
# Allow a port only from one subnet
sudo firewall-cmd --permanent --zone=public --add-rich-rule=\
'rule family="ipv4" source address="203.0.113.0/24" port protocol="tcp" port="5432" accept'
# Same, with logging
sudo firewall-cmd --permanent --zone=public --add-rich-rule=\
'rule family="ipv4" source address="203.0.113.0/24" service name="ssh" log prefix="ssh-allowed " level="info" accept'
# Block one address
sudo firewall-cmd --permanent --zone=public --add-rich-rule=\
'rule family="ipv4" source address="198.51.100.7" reject'
sudo firewall-cmd --zone=public --list-rich-rules
sudo firewall-cmd --permanent --zone=public --remove-rich-rule='<exact rule text>'
To remove a rich rule you must pass its text exactly as it was added. Copy it from --list-rich-rules.
Masquerading (NAT)¶
sudo firewall-cmd --zone=external --query-masquerade
sudo firewall-cmd --permanent --zone=external --add-masquerade
sudo firewall-cmd --reload
This is what turns a two-NIC box into a NAT gateway. The complete walk-through, including the interface-to-zone assignments, is in the Linux router guide.
Restarting¶
sudo systemctl restart firewalld # full restart
sudo firewall-cmd --reload # re-read permanent config, keep connections
Cheat sheet¶
firewall-cmd --get-active-zones
firewall-cmd --zone=<zone> --list-all
firewall-cmd --permanent --zone=<zone> --add-service=<svc>
firewall-cmd --permanent --zone=<zone> --add-port=<port>/tcp
firewall-cmd --permanent --zone=<zone> --add-masquerade
firewall-cmd --reload