iptables: Building Firewalls on Linux

In the previous chapter, we learned that netfilter is the Linux kernel framework responsible for packet filtering, NAT, and packet manipulation. However, the kernel itself does not provide a convenient way to configure these rules.

For many years, that role was filled by iptables.

Although modern Linux distributions are gradually adopting nftables, iptables remains widely used. Many production servers, cloud images, embedded systems, appliances, and existing automation still rely on it. Understanding iptables is therefore an important skill, even if you primarily use nftables in new deployments.

In this chapter, you'll learn how iptables is organized, how packets are matched against rules, and how to build simple but practical firewalls.


What is iptables?

iptables is a userspace utility that configures the IPv4 packet filtering rules inside the Linux kernel.

It allows administrators to define rules that decide whether packets should be:

  • accepted,
  • dropped,
  • rejected,
  • logged,
  • modified,
  • or passed to another chain for additional processing.

Remember:

iptables is not the firewall itself. It is the tool used to configure the netfilter firewall inside the Linux kernel.


Checking Your System

Before working with iptables, determine whether your system uses it directly or through the newer nftables backend.

iptables --version

Example:

iptables v1.8.11 (nf_tables)

or

iptables v1.8.11 (legacy)
  • legacy means the classic kernel backend.
  • nf_tables means the iptables command is translating rules into nftables.

Fortunately, the command syntax remains nearly identical.


The iptables Architecture

iptables organizes rules into three levels:

Tables
    └── Chains
            └── Rules

For example:

filter
├── INPUT
├── OUTPUT
└── FORWARD

Each rule is evaluated in order until a decision is made.

Think of it like this:

Incoming packet
       │
       ▼
Rule 1 ? No
       │
Rule 2 ? No
       │
Rule 3 ? Yes
       │
       ▼
 DROP

Rule order is extremely important.


Tables

Most administrators only interact with a few tables.

filter

The default table.

Responsible for:

  • firewall rules
  • allowing traffic
  • blocking traffic

You'll spend most of your time here.


nat

Responsible for:

  • Source NAT
  • Destination NAT
  • Port forwarding
  • Masquerading

mangle

Used to modify packet headers.

Examples include:

  • changing TTL
  • modifying DSCP
  • packet marking

raw

Allows special packet processing before connection tracking.

Mostly used in advanced networking environments.


Chains

Inside each table are chains.

The filter table contains:

INPUT
OUTPUT
FORWARD

Each corresponds to a netfilter hook you learned previously.

INPUT

Packets destined for the local machine.

Example:

SSH connections.


OUTPUT

Packets generated locally.

Example:

A web request made by curl.


FORWARD

Packets routed through the machine.

Example:

Linux acting as a router.


Rule Matching

A rule contains two parts:

  • match conditions
  • target (action)

Example:

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

Breaking it apart:

-A INPUT

Append to INPUT chain.

-p tcp

Match TCP packets.

--dport 22

Destination port 22.

-j ACCEPT

Accept the packet.

A packet that does not match simply continues to the next rule.


Targets

The most common targets are:

TargetDescription
ACCEPTAllow packet
DROPSilently discard
REJECTReject and notify sender
LOGLog packet
RETURNReturn to calling chain

Listing Rules

Display every rule:

sudo iptables -L

Show numeric addresses:

sudo iptables -L -n

Show packet counters:

sudo iptables -L -v -n

Example:

Chain INPUT

pkts bytes target
245 18340 ACCEPT
12   720 DROP

The counters are extremely useful when debugging.


Rule Order Matters

Consider these rules:

1 ACCEPT tcp port 22
2 DROP all

SSH works.

Now reverse them:

1 DROP all
2 ACCEPT tcp port 22

SSH never reaches rule 2.

iptables always evaluates rules from top to bottom.

The first matching rule wins.


Default Policies

Every chain has a default policy.

Check it:

sudo iptables -L

Example:

Chain INPUT (policy ACCEPT)

or

Chain INPUT (policy DROP)

If no rule matches, the default policy determines what happens.


Hands-on Lab: Create a Simple Firewall

Warning

Perform these labs on a virtual machine. An incorrect firewall rule can lock you out of a remote server.


Step 1

Display current rules.

sudo iptables -L -n -v

Initially you may see:

Chain INPUT (policy ACCEPT)

Step 2

Allow SSH.

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

Step 3

Allow ICMP.

sudo iptables -A INPUT -p icmp -j ACCEPT

Step 4

Drop everything else.

sudo iptables -A INPUT -j DROP

Your rule set becomes:

INPUT

Allow SSH

Allow ICMP

Drop everything else

Test:

ping server

Should succeed.

Then:

curl http://server

Should fail.


Hands-on Lab: Logging

Sometimes you don't want to drop traffic immediately.

Instead, log it.

sudo iptables -A INPUT -j LOG --log-prefix "DROP: "

Logs can be viewed using:

journalctl -k

or

dmesg

Logging is invaluable during firewall development.


Hands-on Lab: Packet Counters

Generate traffic:

ping localhost

Now inspect:

sudo iptables -L -v -n

Notice how packet and byte counters increase.

These counters help answer questions like:

  • Is the rule matching?
  • How often?
  • Is this rule ever used?

Inserting Rules

Appending is not always enough.

Suppose you already have:

1 DROP all

Adding:

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

doesn't help.

Instead:

sudo iptables -I INPUT 1 -p tcp --dport 22 -j ACCEPT

The rule is inserted at position 1.

Always remember:

  • -A appends
  • -I inserts

Deleting Rules

List rules with numbers:

sudo iptables -L --line-numbers

Example:

1 ACCEPT tcp 22

2 DROP all

Delete rule 2:

sudo iptables -D INPUT 2

Flushing Rules

Remove every rule:

sudo iptables -F

This flushes the current table.

It does not change default policies.

Be careful on production servers.


Saving Rules

Unlike configuration files, iptables rules exist only in kernel memory.

After a reboot, they disappear unless saved.

Different Linux distributions use different mechanisms.

Examples include:

  • iptables-save
  • iptables-restore
  • netfilter-persistent
  • distribution-specific startup scripts

We'll keep persistence outside the scope of this chapter because it varies across distributions.


Common Mistakes

Forgetting Loopback

Blocking loopback breaks many applications.

Always allow it.


Blocking Established Connections

Without stateful rules, replies to existing connections may be blocked.

We'll improve our firewall after learning connection tracking.


Testing Through SSH

Always be careful when modifying firewall rules over SSH.

A single incorrect rule can disconnect your session.

Whenever possible:

  • use a VM,
  • keep another console open,
  • or have out-of-band access.

Best Practices

  • Keep rules simple.
  • Comment complex rules.
  • Put specific rules before general ones.
  • Monitor packet counters.
  • Test incrementally.
  • Understand every rule before deploying it.

Remember:

A firewall should be predictable. Complexity often creates security problems rather than solving them.


Looking Ahead

The examples in this chapter intentionally avoided stateful filtering. Every rule treated packets independently.

In real production environments, almost every firewall relies on connection tracking.

Instead of writing rules that allow both directions of every connection, the firewall can recognize packets that belong to an already established flow.

That makes rule sets both simpler and more secure.

We'll explore that in the next chapter on Connection Tracking, and later revisit firewall design using stateful rules.


Summary

  • iptables is the traditional userspace interface for configuring netfilter.
  • Rules are organized into tables, chains, and rules.
  • Packets are evaluated from top to bottom.
  • The first matching rule determines the outcome.
  • Rule order is critical.
  • The filter table is used for firewalling.
  • Packet counters are valuable for troubleshooting.
  • Rules are stored in kernel memory and must be saved separately if they should survive a reboot.
  • Understanding iptables makes it much easier to understand existing Linux systems, even if new deployments use nftables.