firewalld Cheat Sheet: firewall-cmd Rules, Commands and Examples (RHEL/Fedora)

On RHEL, Rocky Linux, AlmaLinux, and Fedora, firewalld manages host firewall rules through zones and services. The firewall-cmd CLI opens ports, assigns interfaces to zones, and applies rich rules without restarting the whole firewall stack.

Published

Updated

Read time 10 min read

Reviewed byDeepak Prasad

firewalld Cheat Sheet: firewall-cmd Rules, Commands and Examples (RHEL/Fedora)
About On RHEL, Rocky Linux, AlmaLinux, and Fedora, firewalld manages host firewall rules through zones and services. The firewall-cmd CLI opens ports, assigns interfaces to zones, and applies rich rules without restarting the whole firewall stack.
Tested on RHEL 9.4; firewalld 1.2.5
Man page firewall-cmd(1)
Privilege root / sudo
Distros

RHEL, Rocky Linux, AlmaLinux, CentOS Stream, and Fedora (default host firewall).

Ubuntu and Debian use ufw or nftables directly

Related guide

firewall-cmd — quick reference

Status and reload

Check whether firewalld is running and apply configuration changes.

When to use Command
Check if firewalld is active sudo firewall-cmd --state
Reload runtime rules from permanent config sudo firewall-cmd --reload
Full reload (drops connections; severe issues only) sudo firewall-cmd --complete-reload
Copy working runtime rules into permanent config sudo firewall-cmd --runtime-to-permanent
Show firewalld version firewall-cmd --version

Zones

Zones group rules by trust level (public, internal, trusted, drop, …).

When to use Command
List all zone names sudo firewall-cmd --get-zones
Show zones bound to interfaces right now sudo firewall-cmd --get-active-zones
Show the default zone for new interfaces sudo firewall-cmd --get-default-zone
Change the default zone sudo firewall-cmd --set-default-zone=public
Show full config for the default zone sudo firewall-cmd --list-all
Show full config for one zone sudo firewall-cmd --list-all --zone=public
Dump every zone sudo firewall-cmd --list-all-zones
See which zone owns an interface sudo firewall-cmd --get-zone-of-interface=eth0
Assign an interface to a zone (runtime) sudo firewall-cmd --zone=public --add-interface=eth0
Move an interface to another zone sudo firewall-cmd --zone=internal --change-interface=eth0

Services and ports

Open application traffic with predefined services or explicit port/protocol pairs.

When to use Command
Allow HTTP in the active zone (runtime) sudo firewall-cmd --add-service=http
Allow HTTPS permanently sudo firewall-cmd --add-service=https --permanent
Allow SSH permanently sudo firewall-cmd --add-service=ssh --permanent
Remove a service sudo firewall-cmd --remove-service=http --permanent
Open TCP port 8080 permanently sudo firewall-cmd --add-port=8080/tcp --permanent
Open UDP port 53 permanently sudo firewall-cmd --add-port=53/udp --permanent
Remove a port sudo firewall-cmd --remove-port=8080/tcp --permanent
List allowed services sudo firewall-cmd --list-services
List open ports sudo firewall-cmd --list-ports

After --permanent changes, run sudo firewall-cmd --reload so runtime matches disk.

Sources, forwarding, and NAT

When to use Command
Trust traffic from one IP in the zone sudo firewall-cmd --add-source=192.168.1.100 --permanent
Trust a subnet sudo firewall-cmd --add-source=192.168.1.0/24 --permanent
Enable masquerading (NAT) in a zone sudo firewall-cmd --zone=public --add-masquerade --permanent
Forward local port 80 to 8080 sudo firewall-cmd --add-forward-port=port=80:proto=tcp:toport=8080 --permanent
Forward port 80 to another host sudo firewall-cmd --add-forward-port=port=80:proto=tcp:toaddr=192.168.1.10 --permanent
List forward-port rules sudo firewall-cmd --list-forward-ports

Rich rules and logging

Fine-grained allow/drop/reject by source, port, or rate limit. To verify whether inbound ICMP still works before blocking echo-request, use ping command from a client host.

When to use Command
Allow SSH from one IP sudo firewall-cmd --add-rich-rule='rule family="ipv4" source address="192.168.1.100" service name="ssh" accept' --permanent
Drop traffic from one IP sudo firewall-cmd --add-rich-rule='rule family="ipv4" source address="203.0.113.50" drop' --permanent
List rich rules sudo firewall-cmd --list-rich-rules
Log all denied packets sudo firewall-cmd --set-log-denied=all
Block inbound ping (ICMP echo-request) sudo firewall-cmd --add-icmp-block=echo-request --permanent

Permanent zones and service control

firewalld runs as a systemd unit; start and enable it with the systemctl command before relying on firewall-cmd rules at boot.

When to use Command
Create a new permanent zone sudo firewall-cmd --permanent --new-zone=appzone
Delete a permanent zone sudo firewall-cmd --permanent --delete-zone=appzone
Start firewalld now sudo systemctl start firewalld
Enable firewalld at boot sudo systemctl enable firewalld

firewall-cmd — command syntax

Synopsis from firewall-cmd(1) on firewalld.org:

text
firewall-cmd [OPTIONS...]

Runtime changes apply immediately but are lost on reboot unless you also pass --permanent and run --reload. Permanent rules live under /etc/firewalld/ (zones, services, policies). firewalld on RHEL 8+ uses nftables as the backend; older releases used iptables.


firewall-cmd — command examples

Essential Inspect the active firewall zone

Start troubleshooting by seeing which zone is default, which interfaces are bound, and what services and ports are already open.

Run the commands:

bash
sudo firewall-cmd --state
sudo firewall-cmd --get-default-zone
sudo firewall-cmd --get-active-zones
sudo firewall-cmd --list-all

Sample output:

text
running
public
public
  interfaces: eth0
  services: cockpit dhcpv6-client ssh
  ports:
  protocols:
  forward: no
  masquerade: no
  rich rules:

The list-all block is for the default zone unless you pass --zone=NAME.

Essential Open SSH and a web server permanently

On a fresh server, allow remote admin and HTTP/HTTPS, then reload so rules survive reboot.

Run the commands:

bash
sudo firewall-cmd --add-service=ssh --permanent
sudo firewall-cmd --add-service=http --permanent
sudo firewall-cmd --add-service=https --permanent
sudo firewall-cmd --reload

Confirm services are listed:

bash
sudo firewall-cmd --list-services

Sample output:

text
cockpit dhcpv6-client http https ssh

Always keep SSH open before tightening the default zone to something restrictive like drop.

Essential Open a custom TCP port

When an app listens on a non-standard port (8080), add an explicit port rule — predefined services will not cover it.

Run the commands:

bash
sudo firewall-cmd --add-port=8080/tcp --permanent
sudo firewall-cmd --reload
sudo firewall-cmd --list-ports

Sample output:

text
8080/tcp

Match the protocol: /udp for DNS-like traffic, /tcp for HTTP-like traffic.

Common Test a rule at runtime, then save it

Runtime rules let you test without reboot risk. When the test works, promote them to permanent config.

Run the commands:

bash
sudo firewall-cmd --add-port=9000/tcp
sudo firewall-cmd --list-ports
sudo firewall-cmd --runtime-to-permanent

Sample output:

text
9000/tcp
success

After --runtime-to-permanent, the open port is stored under /etc/firewalld/ and survives reboot without repeating --add-port.

Common Allow SSH only from a trusted IP

Restrict SSH to one admin workstation instead of the whole internet — use a rich rule with source address and service name.

Run the commands:

bash
sudo firewall-cmd --add-rich-rule='rule family="ipv4" source address="192.168.1.100" service name="ssh" accept' --permanent
sudo firewall-cmd --reload
sudo firewall-cmd --list-rich-rules

Sample output:

text
rule family="ipv4" source address="192.168.1.100" service name="ssh" accept

Rich rules stack with normal service rules; review the full effective policy with --list-all.

Common Drop traffic from a hostile address

Block a known scanner or abusive IP with a drop rich rule — silent discard with no reply.

Run the commands:

bash
sudo firewall-cmd --add-rich-rule='rule family="ipv4" source address="203.0.113.50" drop' --permanent
sudo firewall-cmd --reload
sudo firewall-cmd --list-rich-rules

Sample output:

text
rule family="ipv4" source address="203.0.113.50" drop

Use reject instead of drop when you want the sender to receive an ICMP unreachable response.

Advanced Enable NAT and port forwarding

Turn a RHEL host into a simple gateway: masquerade outbound traffic and forward inbound port 80 to an internal web server.

Run the commands:

bash
sudo firewall-cmd --zone=public --add-masquerade --permanent
sudo firewall-cmd --zone=public --add-forward-port=port=80:proto=tcp:toaddr=192.168.1.50:toport=8080 --permanent
sudo firewall-cmd --reload
sudo firewall-cmd --zone=public --query-masquerade
sudo firewall-cmd --list-forward-ports

Sample output:

text
yes
port=80:proto=tcp:toport=8080:toaddr=192.168.1.50

Ensure IP forwarding is enabled in the kernel (net.ipv4.ip_forward=1) when routing between subnets.

Advanced Create a zone for application traffic

Isolate an application NIC in its own zone with a tighter service list than public.

Run the commands:

bash
sudo firewall-cmd --permanent --new-zone=appzone
sudo firewall-cmd --reload
sudo firewall-cmd --zone=appzone --add-service=http --permanent
sudo firewall-cmd --zone=appzone --add-interface=eth1 --permanent
sudo firewall-cmd --reload
sudo firewall-cmd --zone=appzone --list-all

Sample output:

text
appzone (active)
  interfaces: eth1
  services: http
  ports:
  protocols:
  forward: no
  masquerade: no
  rich rules:

Custom zones live as XML under /etc/firewalld/zones/.

Advanced Verify rules when a service is unreachable

When connectivity fails, confirm the interface zone, open ports, and whether firewalld is running.

Run the commands:

bash
sudo firewall-cmd --get-zone-of-interface=eth0
sudo firewall-cmd --list-all --zone=public
sudo firewall-cmd --list-ports
sudo journalctl -u firewalld --no-pager -n 20

Sample output:

text
public
public (active)
  interfaces: eth0
  services: ssh
  ports: 8080/tcp
...

If the service is allowed in permanent config but not runtime, run sudo firewall-cmd --reload.


firewall-cmd — when to use / when not

Use firewalld / firewall-cmd whenUse something else when
  • You administer RHEL, Rocky, AlmaLinux, or Fedora where firewalld is the default host firewall
  • You want zone-based policies (public vs internal vs trusted) tied to interfaces
  • You need to change rules without restarting the firewall daemon for most updates
  • You prefer named services (http, ssh) over raw iptables syntax
  • You are on Ubuntu or Debian — use ufw or nftables/iptables directly
  • You need cloud SG-style rules only at the hypervisor — host firewalld is optional
  • You already manage everything with low-level nftables scripts and do not want a second layer
  • firewalld is not installed — do not assume firewall-cmd exists on every Linux distro

firewalld vs ufw vs iptables

firewalld ufw iptables / nftables
Default on RHEL, Fedora, Rocky, Alma Ubuntu, Debian Universal (manual setup)
Model Zones + services + rich rules Simple allow/deny profiles Raw rule chains
Runtime vs permanent Built-in dual config ufw rules persist in one layer Depends on save mechanism
Backend nftables (RHEL 8+) iptables/nftables via alternatives Direct kernel rules

firewalld is a manager — it translates zone changes into nftables/iptables rules. On RHEL 8+, inspect the backend with sudo firewall-cmd --info-zone=public.


Host firewall and network troubleshooting nearby.

Command One line
firewall-cmd firewalld CLI (this page)
ss See listening sockets and ports
nmcli Manage interfaces that firewalld zones bind to
tcpdump Capture packets when rules behave unexpectedly

Browse the full index in our Linux commands reference.


firewall-cmd — interview corner

What is firewalld and how does it differ from iptables?

firewalld is a dynamic firewall manager on RHEL-family Linux. You define zones (public, internal, trusted, …), services (ssh, http), ports, and rich rules. firewalld pushes those definitions into nftables (RHEL 8+) or iptables without a full service restart for most changes.

iptables/nftables are the low-level rule engines. firewalld sits above them so admins think in trust zones instead of chain syntax.

Check state:

bash
sudo firewall-cmd --state

A strong answer is:

"firewalld is the high-level host firewall on RHEL and Fedora — zones, services, and rich rules — backed by nftables. iptables is the low-level rule engine; firewalld translates zone policy into kernel rules."

What is the difference between runtime and permanent firewall rules?

firewalld keeps two configurations:

Layer Lifetime Storage
Runtime Until reboot or --reload Active in memory
Permanent Survives reboot Files under /etc/firewalld/

Example workflow:

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

Use runtime-only for quick tests; add --permanent and --reload (or --runtime-to-permanent) for production.

A strong answer is:

"Runtime rules apply immediately but disappear on reboot. Permanent rules live in /etc/firewalld and need --reload to hit runtime. I test with runtime, then --permanent plus reload for persistence."

What is a firewalld zone?

A zone is a named rule set describing how much you trust traffic arriving on attached interfaces. Examples:

Zone Typical use
public Default untrusted LAN or internet-facing NIC
internal Trusted office LAN
trusted Accept nearly everything
drop Silently discard inbound

List bindings:

bash
sudo firewall-cmd --get-active-zones

Each interface maps to one zone; all traffic on that NIC inherits that zone's services and rich rules.

A strong answer is:

"A zone is a trust profile — public, internal, trusted, drop. Interfaces bind to one zone; their traffic gets that zone's allowed services and rules. I check bindings with get-active-zones."

When do you use firewalld rich rules?

Rich rules express conditions plain --add-service cannot — source IP, port + protocol together, rate limits, logging, reject vs drop.

Example — SSH from one admin IP only:

bash
sudo firewall-cmd --add-rich-rule='rule family="ipv4" source address="192.168.1.100" service name="ssh" accept' --permanent

Use services/ports for simple holes; rich rules for micro-segmentation and logging.

A strong answer is:

"Rich rules handle fine-grained policy — source IP, port/protocol combos, logging, rate limits. I use --add-service for simple cases and rich rules when I need allow-from-one-IP or drop-with-log."

What do you use instead of firewalld on Ubuntu?

Ubuntu and Debian ship ufw (Uncomplicated Firewall) as the friendly front end, backed by nftables or iptables. There is no firewall-cmd unless you install firewalld manually.

Rough mapping:

Task firewalld ufw
Allow HTTP firewall-cmd --add-service=http --permanent ufw allow 80/tcp
Allow SSH firewall-cmd --add-service=ssh --permanent ufw allow OpenSSH
Status firewall-cmd --state ufw status

On either distro you can still drop to nft/iptables for advanced cases.

A strong answer is:

"Ubuntu defaults to ufw, not firewalld. Same job — allow ports and services — different CLI. I match the tool to the distro rather than assuming firewall-cmd everywhere."


Troubleshooting

Symptom Likely cause What to try
firewall-cmd: command not found firewalld not installed (common on Ubuntu) Install on RHEL/Fedora with dnf install firewalld; on Ubuntu use ufw
Rule missing after reboot Added at runtime only, not --permanent firewall-cmd --list-all; re-add with --permanent and --reload
Service still blocked Wrong zone or interface binding --get-zone-of-interface=NIC; --list-all --zone=NAME
--permanent change not active Forgot --reload sudo firewall-cmd --reload
SSH lost after hardening Removed ssh service or set default zone to drop Console access; restore ssh service in permanent config
Rich rule syntax error Quoting or XML special characters Copy from firewall-cmd --list-rich-rules; test runtime first

Package installs and updates in this section use dnf command.

References

Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive …