iptables is not just a packet filter; it’s a stateful firewall that controls network traffic by matching packets against rules defined in chains and tables.

Let’s see it in action. Imagine a simple web server that should only accept connections on port 80 (HTTP) and port 443 (HTTPS) from anywhere, but should drop all other incoming traffic.

# Allow established and related connections (essential for return traffic)
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# Allow incoming HTTP traffic from anywhere
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT

# Allow incoming HTTPS traffic from anywhere
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# Drop all other incoming traffic by default
sudo iptables -P INPUT DROP

This setup achieves a basic level of security. The INPUT chain processes packets destined for the local machine. The -m conntrack --ctstate ESTABLISHED,RELATED rule is crucial; it allows return packets for connections that the server initiated, or related packets from existing connections, preventing the firewall from blocking legitimate responses. The next two rules explicitly permit traffic on the standard web ports. Finally, -P INPUT DROP sets the default policy for the INPUT chain to DROP, meaning any packet not matched by a preceding ACCEPT rule will be discarded.

The core of iptables lies in its tables and chains. The most common table is filter, which contains three built-in chains: INPUT (for packets destined for the local machine), FORWARD (for packets routed through the machine), and OUTPUT (for packets originating from the local machine). Packets traverse these chains in a specific order.

Beyond basic port filtering, iptables offers powerful features like Network Address Translation (NAT) and packet mangling, though these are configured in different tables (nat and mangle respectively). For instance, you might use the nat table to masquerade outgoing traffic from a private network behind a single public IP address.

# Example: Masquerading for outgoing traffic
sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

Here, -t nat specifies the NAT table, POSTROUTING is a chain in the NAT table that processes packets just before they leave an interface, -o eth0 matches packets exiting the eth0 interface, and -j MASQUERADE performs the translation, dynamically assigning the IP of eth0 to outgoing packets.

When hardening, understanding the order of rule evaluation is paramount. iptables processes rules sequentially within a chain. The first rule that matches a packet determines its fate (e.g., ACCEPT, DROP, REJECT, or jump to another chain). If a packet doesn’t match any rule, the chain’s default policy is applied.

A common mistake is to forget the ESTABLISHED,RELATED rule. Without it, even if you explicitly allow port 80, the server’s responses might be blocked because the return packets don’t originate from an explicitly allowed incoming connection. Another pitfall is setting the default policy to ACCEPT and then trying to DROP specific ports; it’s far more secure to DROP by default and ACCEPT only what’s explicitly needed.

When you’re working with iptables, especially in complex setups, the iptables-save and iptables-restore commands are your best friends for persistence. These commands allow you to save your current firewall rules to a file and then load them back, ensuring your firewall configuration survives reboots.

# Save current rules to a file
sudo iptables-save > /etc/iptables/rules.v4

# Load rules from a file (e.g., after reboot or manual restore)
sudo iptables-restore < /etc/iptables/rules.v4

The most surprising aspect for many is how easily a simple iptables -F (flush all rules) can leave a system wide open, especially if the default policy is ACCEPT. It highlights the fragility of a misconfigured firewall; a single command can undo hours of careful configuration.

The next step after mastering basic filtering and persistence is exploring advanced modules like limit for rate-limiting, state for connection tracking beyond ESTABLISHED,RELATED, and custom iptables chains for better organization.

Want structured learning?

Take the full Iptables course →