firewall-cmdManage firewalld zones, services and ports
firewall-cmd controls firewalld, the default firewall manager on RHEL, Rocky, Alma, CentOS and Fedora. Instead of raw rules you open services and ports in zones, and every change is either runtime (immediate, lost on reload) or permanent (saved, applied on reload).
firewall-cmd [--permanent] [--zone=ZONE] --add-service=S | --add-port=P/PROTO | --add-rich-rule='...' | --list-all | --reloadYou log in to a RHEL-family server for the first time and need to know what the firewall lets in.
sudoChanges need root (or polkit authorisation); without it you get 'Authorization failed'.
firewalld is a daemon that owns the host's netfilter rules (through nftables on current releases); firewall-cmd sends it requests over D-Bus. Its model is zones: each network interface or source address range belongs to one zone (public, internal, trusted, drop...), and each zone lists what is allowed in: services (named bundles of ports from /usr/lib/firewalld/services/*.xml, such as ssh = 22/tcp), plain ports, rich rules for finer conditions, masquerading and port forwards. A packet is handled by the zone of its source address if one matches, otherwise by the zone of the interface it arrived on. Every setting exists twice: the runtime configuration in the kernel right now, and the permanent configuration in /etc/firewalld/zones/*.xml. --permanent edits only the latter; --reload replaces the runtime with the permanent one, discarding runtime-only changes. firewalld 2.x (Fedora, RHEL 10, Ubuntu 24.04) also prints ingress/egress priorities in --list-all; RHEL 9's 1.x output doesn't have those lines.
--stateIs firewalld running?--get-default-zone / --get-active-zonesDefault zone / zones in use with their interfaces and sources--list-all [--zone=Z]Everything a zone allows--add-service=S / --remove-service=SOpen or close a named service (ssh, http, https...)--add-port=N/tcpOpen a port or range (8000-8100/tcp)--permanentChange the saved config instead of the running one--reloadLoad the permanent config into the runtime--runtime-to-permanentSave the current runtime config as permanent--zone=Z --add-source=CIDRSend traffic from a source range to zone Z--add-rich-rule='rule ...'Detailed rule: source, port, log, limit, accept/reject/drop--get-services / --info-service=SAll service names / ports of one service--add-forward-port=...Port forwarding (DNAT) in a zone--timeout=5mRuntime change that removes itself after the time (safe testing)sudo firewall-cmd --add-port=8080/tcp and moving onIt's a runtime-only change: the next --reload or reboot silently removes it.
sudo firewall-cmd --permanent --add-port=8080/tcp && sudo firewall-cmd --reloadsudo firewall-cmd --permanent --add-service=http and expecting it to work nowPermanent changes don't touch the running firewall until a reload.
Follow it with sudo firewall-cmd --reload (or apply both with and without --permanent).Adding iptables rules by hand on a firewalld hostfirewalld owns the rule set and rebuilds it on reload, dropping your manual rules.
Use rich rules or direct firewalld configuration instead.--add-port=5432/tcp to let the app servers reach the databaseThat opens the port to every source that reaches the zone, including the internet if the host is exposed.
A rich rule with source address=10.0.2.0/24, or a source-based zone.Try these on a Linux machine of your own. Each task has a hint and a solution.
Write the commands to permanently open HTTPS in the default zone and apply the change.
Write the command to permanently allow TCP 9100 (node exporter) only from 10.0.5.0/24.
Read this output and explain what's reachable from outside: 'services: dhcpv6-client ssh ports: 8080/tcp'. Then write the command to close 8080 permanently.
firewall-cmdManage firewalld zones, services and ports
firewall-cmd controls firewalld, the default firewall manager on RHEL, Rocky, Alma, CentOS and Fedora. Instead of raw rules you open services and ports in zones, and every change is either runtime (immediate, lost on reload) or permanent (saved, applied on reload).
firewall-cmd [--permanent] [--zone=ZONE] --add-service=S | --add-port=P/PROTO | --add-rich-rule='...' | --list-all | --reloadYou log in to a RHEL-family server for the first time and need to know what the firewall lets in.
sudoChanges need root (or polkit authorisation); without it you get 'Authorization failed'.
firewalld is a daemon that owns the host's netfilter rules (through nftables on current releases); firewall-cmd sends it requests over D-Bus. Its model is zones: each network interface or source address range belongs to one zone (public, internal, trusted, drop...), and each zone lists what is allowed in: services (named bundles of ports from /usr/lib/firewalld/services/*.xml, such as ssh = 22/tcp), plain ports, rich rules for finer conditions, masquerading and port forwards. A packet is handled by the zone of its source address if one matches, otherwise by the zone of the interface it arrived on. Every setting exists twice: the runtime configuration in the kernel right now, and the permanent configuration in /etc/firewalld/zones/*.xml. --permanent edits only the latter; --reload replaces the runtime with the permanent one, discarding runtime-only changes. firewalld 2.x (Fedora, RHEL 10, Ubuntu 24.04) also prints ingress/egress priorities in --list-all; RHEL 9's 1.x output doesn't have those lines.
--stateIs firewalld running?--get-default-zone / --get-active-zonesDefault zone / zones in use with their interfaces and sources--list-all [--zone=Z]Everything a zone allows--add-service=S / --remove-service=SOpen or close a named service (ssh, http, https...)--add-port=N/tcpOpen a port or range (8000-8100/tcp)--permanentChange the saved config instead of the running one--reloadLoad the permanent config into the runtime--runtime-to-permanentSave the current runtime config as permanent--zone=Z --add-source=CIDRSend traffic from a source range to zone Z--add-rich-rule='rule ...'Detailed rule: source, port, log, limit, accept/reject/drop--get-services / --info-service=SAll service names / ports of one service--add-forward-port=...Port forwarding (DNAT) in a zone--timeout=5mRuntime change that removes itself after the time (safe testing)sudo firewall-cmd --add-port=8080/tcp and moving onIt's a runtime-only change: the next --reload or reboot silently removes it.
sudo firewall-cmd --permanent --add-port=8080/tcp && sudo firewall-cmd --reloadsudo firewall-cmd --permanent --add-service=http and expecting it to work nowPermanent changes don't touch the running firewall until a reload.
Follow it with sudo firewall-cmd --reload (or apply both with and without --permanent).Adding iptables rules by hand on a firewalld hostfirewalld owns the rule set and rebuilds it on reload, dropping your manual rules.
Use rich rules or direct firewalld configuration instead.--add-port=5432/tcp to let the app servers reach the databaseThat opens the port to every source that reaches the zone, including the internet if the host is exposed.
A rich rule with source address=10.0.2.0/24, or a source-based zone.Try these on a Linux machine of your own. Each task has a hint and a solution.
Write the commands to permanently open HTTPS in the default zone and apply the change.
Write the command to permanently allow TCP 9100 (node exporter) only from 10.0.5.0/24.
Read this output and explain what's reachable from outside: 'services: dhcpv6-client ssh ports: 8080/tcp'. Then write the command to close 8080 permanently.