iptables & firewalld Cheat Sheet
Manage Linux firewall rules directly with iptables, or through firewalld's zones on Fedora/RHEL, without locking yourself out.
A practical reference for the two firewall tools you’ll meet when ufw isn’t available: iptables, the classic low-level packet filter, and firewalld, the zone-based front end used by default on Fedora/RHEL/Rocky/Alma (much like ufw is to Debian/Ubuntu).
What they actually are
iptables talks almost directly to the kernel’s packet filter (netfilter) — you build an ordered list of rules per chain, and the first match wins. firewalld sits on top of the same underlying filter and adds a friendlier, zone-based model with runtime vs. permanent configuration. Pick whichever your distribution already ships; don’t run both at once.
Most important warning: allow SSH before anything else
On a remote server, setting a default-deny policy or reloading firewall rules without an explicit SSH allow rule will drop your session and lock you out. Always add the SSH rule first, and keep a second connection (or your cloud provider’s console) open while testing.
Checking current status
sudo iptables -L -n -v # list all rules, numeric addresses, with packet/byte counters
sudo firewall-cmd --state # is firewalld running at all
sudo firewall-cmd --list-all # rules, services and ports for the active zone
Allow SSH first
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT # append a rule allowing inbound SSH
sudo firewall-cmd --add-service=ssh --permanent # allow SSH, saved across reboots
sudo firewall-cmd --reload # apply the permanent config to the running firewall
Default policies (iptables chains)
sudo iptables -P INPUT DROP # drop anything inbound that isn't explicitly allowed
sudo iptables -P FORWARD DROP # drop anything this host would otherwise route through
sudo iptables -P OUTPUT ACCEPT # let the host itself make outbound connections freely
Set policies after your allow rules are already in place (starting with SSH) — a
DROPpolicy applied before that will cut your own session immediately.
Allowing common ports
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT # HTTP
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT # HTTPS
sudo iptables -A INPUT -p udp --dport 53 -j ACCEPT # DNS
sudo firewall-cmd --add-service=http --permanent # HTTP, by service name
sudo firewall-cmd --add-service=https --permanent # HTTPS
sudo firewall-cmd --add-port=8080/tcp --permanent # an arbitrary port, by number
sudo firewall-cmd --reload # apply the permanent changes
Allowing from a specific IP address
sudo iptables -A INPUT -s 203.0.113.10 -j ACCEPT # allow everything from this one address
sudo firewall-cmd --add-source=203.0.113.10 --permanent # trust this address in the current zone
sudo firewall-cmd --reload
Blocking a port or an address
sudo iptables -A INPUT -s 198.51.100.55 -j DROP # silently drop traffic from this address
sudo iptables -A INPUT -p tcp --dport 23 -j REJECT # actively refuse Telnet, tells the sender
DROP gives no response at all (the connection just hangs); REJECT sends back an explicit refusal — useful during testing, less useful for hiding that a port is closed.
sudo firewall-cmd --add-rich-rule='rule family="ipv4" source address="198.51.100.55" reject' --permanent # block one address
sudo firewall-cmd --reload
Rule order matters (iptables)
sudo iptables -I INPUT 1 -s 198.51.100.55 -j DROP # insert at position 1, ahead of existing allow rules
Rules are evaluated top to bottom, first match wins — -A appends to the end of the chain, -I inserts at a given position. A DROP added after a broader ACCEPT further up will never be reached.
Viewing rules with line numbers, and deleting
sudo iptables -L INPUT --line-numbers # show each rule's position, needed to delete by number
sudo iptables -D INPUT 3 # delete rule number 3 from the INPUT chain
sudo firewall-cmd --remove-service=http --permanent # remove a previously-allowed service
sudo firewall-cmd --remove-port=8080/tcp --permanent # remove a previously-allowed port
sudo firewall-cmd --reload
Saving rules so they survive a reboot
iptables rules live only in memory until you save them — a reboot silently reverts to nothing.
sudo apt install iptables-persistent # Debian/Ubuntu: installing this also prompts to save current rules
sudo netfilter-persistent save # save the current rule set for next boot
firewalld doesn’t have this problem: anything added with --permanent is already written to disk, --reload just makes it active immediately too.
firewalld zones (brief)
sudo firewall-cmd --get-active-zones # which zone each network interface is using
sudo firewall-cmd --get-default-zone # the zone new interfaces get by default
sudo firewall-cmd --zone=public --list-all # rules for a specific zone
A zone is a named trust level (public, internal, trusted, etc.) with its own rule set — an interface facing the internet and one facing an internal LAN can sit in different zones with very different rules, instead of one flat list for everything.
Flushing all rules
sudo iptables -F # remove every rule from every chain - policies (DROP/ACCEPT) are untouched
-Fdoes not reset the chain policies. IfINPUT’s policy is alreadyDROP, flushing the rules that allowed your own SSH connection will lock you out immediately — this is one of the most common ways people lose remote access to a server.
Safety notes
- Always allow SSH (or your actual management port) before setting a default-deny policy or reloading rules.
- Keep a second session or an out-of-band console (cloud provider dashboard, serial console) open while testing any firewall change.
- Prefer
firewall-cmd’s--permanent+--reloadpattern over guessing whether a rawiptablesrule set was saved — an unsaved rule silently disappears on reboot. - Test on a non-production host first when you’re unsure how a rule set interacts with existing ones — rule order matters and mistakes are easy to make.