Back to Linux guides

Iptables vs Firewalld

Stanley Ulili
Updated on December 15, 2025

Linux firewall management is going through a generational transition. For over two decades, iptables has been the standard tool for controlling network traffic on Linux systems. But firewalld has emerged as the preferred solution on Red Hat-based distributions, bringing a different philosophy to packet filtering.

Iptables connects directly to the kernel's netfilter framework, giving you complete control over every aspect of packet filtering. It's powerful and flexible, but that power comes wrapped in complex syntax that takes time to master.

Firewalld sits at a higher level, organizing your firewall around zones and services rather than raw packet filtering rules. It manages iptables or nftables in the background while presenting a more structured interface for common security scenarios.

This guide examines both tools, showing you what makes each one useful and helping you understand which approach fits your infrastructure better.

What iptables brings to Linux

Iptables has been the standard Linux firewall tool since the early 2000s. It provides direct access to the kernel's netfilter packet filtering system, which means you can control exactly how your system handles network traffic.

The tool organizes rules into tables and chains. The most commonly used table is the filter table, which contains three chains: INPUT (for incoming packets), OUTPUT (for outgoing packets), and FORWARD (for packets being routed through the system). Each chain contains rules that match packets based on criteria you specify.

A basic iptables rule looks like this:

 
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT

This appends a rule to the INPUT chain that accepts TCP packets destined for port 22 (SSH). The syntax is precise but dense - every flag matters, and the order of parameters can be significant.

Iptables handles both IPv4 and IPv6 traffic through separate commands: iptables for IPv4 and ip6tables for IPv6. This separation means you often need to write two versions of each rule to cover both protocols.

The tool excels at granular control. You can match packets based on source and destination addresses, ports, protocols, connection states, TCP flags, packet length, and dozens of other criteria. You can modify packet headers, redirect traffic, implement complex NAT configurations, and create sophisticated routing policies.

But this power comes with a learning curve. Iptables syntax is notoriously difficult to remember, especially for complex rules. The command structure is verbose and unforgiving - miss a flag or get the order wrong, and your rule either fails or does something unexpected.

With iptables' low-level approach established, you can see how firewalld takes a completely different path by adding structure and abstraction.

How firewalld organizes security

Firewalld appeared in the early 2010s as part of Red Hat's effort to modernize Linux firewall management. Instead of thinking about individual packet filtering rules, firewalld encourages you to think about network zones and services.

A zone represents a level of trust for network connections. The default zones include public (untrusted networks), home (trusted home network), work (corporate network), internal (private networks), dmz (public-facing services), and trusted (completely trusted networks).

Each network interface on your system gets assigned to a zone, and the zone determines what traffic is allowed. This maps better to how people actually think about network security - you trust your home network more than random public WiFi, so you apply different rules to each.

Services define what ports and protocols applications need. Instead of remembering that SSH uses port 22 and HTTP uses port 80, you reference services by name:

 
sudo firewall-cmd --zone=public --add-service=ssh
 
sudo firewall-cmd --zone=public --add-service=http

Firewalld includes service definitions for hundreds of common applications. Each service is defined in an XML file that specifies all the ports and protocols that application needs.

The tool separates runtime and permanent configurations. Changes you make without the --permanent flag take effect immediately but don't survive reboots. This lets you test changes safely before committing them.

Firewalld manages iptables rules automatically. Every zone, service, and rule you configure in firewalld gets translated into iptables rules that netfilter actually uses. On newer systems, firewalld can use nftables instead as its backend.

The zone-based model adds conceptual overhead initially but provides better organization for complex network configurations. Understanding both philosophies helps, but seeing them side by side makes the practical differences clearer.

Comparing approaches and capabilities

These tools operate at different abstraction levels, which affects everything about how you use them:

Aspect iptables firewalld
Abstraction level Low-level packet filtering High-level zone management
Primary model Chains and rules Zones and services
IPv4/IPv6 handling Separate commands Unified interface
Configuration persistence Manual save/restore Automatic
Runtime changes Immediate, permanent Separate runtime/permanent
Service definitions None XML-based service files
Zone concept Not supported Core organizational principle
Default policies Per-chain policies Per-zone defaults
Rule inspection List chains with rules List zones with services
Backend flexibility Direct netfilter interface Can use iptables or nftables
NetworkManager integration None Automatic zone switching
Rich rules Not a concept Multi-criteria rules
Logging Manual rule configuration Integrated per-zone logging
Desktop integration None firewall-config GUI
Distribution adoption Universal RHEL, Fedora, CentOS, SUSE

These architectural differences become concrete when you start creating actual firewall rules.

Writing rules with iptables

Iptables requires understanding its structure before you can create even simple rules. You work directly with chains, matches, and targets.

Setting default policies determines what happens to packets that don't match any rules:

 
sudo iptables -P INPUT DROP
 
sudo iptables -P FORWARD DROP
 
sudo iptables -P OUTPUT ACCEPT

These commands set the INPUT and FORWARD chains to drop unmatched packets while allowing all outgoing traffic.

Allowing SSH access:

 
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT

Allowing established connections prevents you from needing rules for every response packet:

 
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

Restricting SSH to a specific network:

 
sudo iptables -A INPUT -p tcp -s 192.168.1.0/24 --dport 22 -j ACCEPT

Viewing your configuration:

 
sudo iptables -L -v -n
Output
Chain INPUT (policy DROP 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
  421 33680 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:22
 1524 121920 ACCEPT    all  --  *      *       0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED

Deleting rules requires knowing their position:

 
sudo iptables -L INPUT --line-numbers
 
sudo iptables -D INPUT 1

For IPv6, you need separate commands that mirror your IPv4 rules. Maintaining parallel rulesets doubles your work and creates opportunities for inconsistencies.

Having seen iptables' manual approach, examining firewalld shows how zone-based organization changes the workflow.

Managing zones with firewalld

Firewalld's zone system requires a different mental model but provides better organization for complex networks.

Checking active zones and their interfaces:

 
sudo firewall-cmd --get-active-zones
Output
public
  interfaces: eth0
internal
  interfaces: eth1

Checking what's allowed in a zone:

 
sudo firewall-cmd --zone=public --list-all
Output
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: eth0
  sources: 
  services: dhcpv6-client ssh
  ports: 
  protocols: 
  forward: no
  masquerade: no

Adding a service to a zone (runtime only):

 
sudo firewall-cmd --zone=public --add-service=http

Making it permanent:

 
sudo firewall-cmd --zone=public --add-service=http --permanent

Or make all runtime changes permanent at once:

 
sudo firewall-cmd --runtime-to-permanent

Opening a specific port:

 
sudo firewall-cmd --zone=public --add-port=8080/tcp --permanent
 
sudo firewall-cmd --reload

Restricting access with rich rules:

 
sudo firewall-cmd --zone=public --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" service name="ssh" accept' --permanent

Creating a custom service requires an XML file:

/etc/firewalld/services/myapp.xml
<?xml version="1.0" encoding="utf-8"?>
<service>
  <short>MyApp</short>
  <description>Custom application requiring multiple ports</description>
  <port protocol="tcp" port="8080"/>
  <port protocol="tcp" port="8443"/>
</service>

After reloading, you can use it like any built-in service. The zone-based workflow takes more setup initially but scales better as your network grows more complex.

Advanced networking features

Where iptables and firewalld truly differ is in handling complex scenarios.

Port forwarding with iptables requires working with the nat table:

 
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to-destination 192.168.1.100:80
 
sudo iptables -A FORWARD -p tcp -d 192.168.1.100 --dport 80 -j ACCEPT

Firewalld handles the same operation with one command:

 
sudo firewall-cmd --zone=public --add-forward-port=port=80:proto=tcp:toport=8080:toaddr=192.168.1.100 --permanent

Masquerading (NAT for internet sharing) with iptables:

 
sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
 
sudo iptables -A FORWARD -i eth1 -o eth0 -j ACCEPT

With firewalld:

 
sudo firewall-cmd --zone=external --add-masquerade --permanent

Rate limiting in iptables uses the recent module:

 
sudo iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -m recent --set
 
sudo iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -m recent --update --seconds 60 --hitcount 4 -j DROP

Firewalld's rich rules provide complex matching in a more readable format:

 
sudo firewall-cmd --zone=public --add-rich-rule='rule family="ipv4" source address="10.0.0.0/8" service name="ssh" log prefix="SSH-10NET" level="info" accept' --permanent

Firewalld's abstractions make common operations simpler but give you less control over exactly how packets are processed. With capabilities covered, examining persistence shows different operational approaches.

Configuration persistence and management

Iptables rules exist only in memory until you explicitly save them. After making changes, you need distribution-specific commands to save them.

On Debian and Ubuntu:

 
sudo apt install iptables-persistent
 
sudo netfilter-persistent save

Or manually:

 
sudo iptables-save > /etc/iptables/rules.v4

The saved file format is iptables-restore's input format, which you can edit directly for bulk changes.

Firewalld handles persistence automatically. Every change you make with the --permanent flag gets written immediately:

 
sudo firewall-cmd --zone=public --add-service=http --permanent

Configuration lives in XML files in /etc/firewalld/zones/:

/etc/firewalld/zones/public.xml
<?xml version="1.0" encoding="utf-8"?>
<zone>
  <short>Public</short>
  <service name="ssh"/>
  <service name="dhcpv6-client"/>
  <service name="http"/>
</zone>

Backing up with iptables:

 
sudo iptables-save > /backup/firewall-$(date +%Y%m%d).rules

With firewalld:

 
sudo tar -czf /backup/firewalld-$(date +%Y%m%d).tar.gz /etc/firewalld

Both formats version control cleanly with Git, though firewalld's XML is more human-readable while iptables-save format is more compact.

Integration and automation

Iptables operates independently of most system services. Logging goes through the kernel to syslog, which provides detailed packet information but isn't easy to parse.

Firewalld integrates more deeply with modern Linux. NetworkManager can automatically switch firewall zones when you connect to different networks. Logging connects through journald, making firewall events appear alongside other system events.

Both tools work with configuration management. Ansible example for iptables:

iptables-playbook.yml
- name: Allow SSH
  iptables:
    chain: INPUT
    protocol: tcp
    destination_port: 22
    jump: ACCEPT

- name: Save rules
  shell: netfilter-persistent save

Ansible example for firewalld:

firewalld-playbook.yml
- name: Allow SSH
  firewalld:
    service: ssh
    permanent: yes
    state: enabled

- name: Reload firewalld
  command: firewall-cmd --reload

The firewalld module maps more naturally to firewalld's concepts, while iptables requires thinking about chains and rules even in Ansible.

Learning curves and expertise requirements

Iptables demands understanding of networking fundamentals - chains, tables, connection states, default policies, and rule evaluation order. Most people need several days before feeling comfortable, and weeks or months for complex scenarios.

The command syntax is dense:

 
sudo iptables -A INPUT -p tcp -s 192.168.1.0/24 -m tcp --dport 8080 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

Firewalld has a gentler curve. The zone concept takes getting used to, but basic operations make intuitive sense:

 
sudo firewall-cmd --zone=public --add-service=http

Most people can secure a basic system within an hour or two. However, rich rules can be as complicated as iptables commands, just with different syntax.

For building deep networking expertise, iptables forces you to learn fundamentals. Firewalld lets you accomplish security tasks without necessarily understanding packet-level details.

Final thoughts

This article looked at iptables and firewalld as two different ways to manage the same underlying firewall system.

Iptables stays important when you need full control and deep network knowledge, and its wide availability makes it a reliable base everywhere. Firewalld builds on top of that with zones and simpler concepts, which fits better when teams are mixed and networks are more complex.

In practice, many setups use both: firewalld for day-to-day management, iptables for special cases. The right choice depends on your distribution, your team’s skills, and how much low-level control you really need.

Got an article suggestion? Let us know
Licensed under CC-BY-NC-SA

This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.