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:
iptablesis 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
iptablescommand 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:
| Target | Description |
|---|---|
| ACCEPT | Allow packet |
| DROP | Silently discard |
| REJECT | Reject and notify sender |
| LOG | Log packet |
| RETURN | Return 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:
-Aappends-Iinserts
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-saveiptables-restorenetfilter-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
iptablesis 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
filtertable 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
iptablesmakes it much easier to understand existing Linux systems, even if new deployments usenftables.