๐Ÿ”ฅ iptables โ€” Linux Firewall

Purpose: iptables is the classic Linux packet filtering and NAT framework. It controls what network traffic is allowed, dropped, or forwarded by the kernel's netfilter subsystem. Despite being superseded by nftables in newer kernels, iptables remains ubiquitous โ€” you will encounter it on virtually every Linux server in production today.
Basic Syntax: iptables [-t TABLE] COMMAND CHAIN [matches] -j TARGET

Default table: filter  |  Other tables: nat  mangle  raw
โš ๏ธ Root required: All iptables commands require root or sudo. Rules are not persistent by default โ€” they live in memory and are lost on reboot. Use iptables-save / iptables-restore or your distro's persistence mechanism (iptables-persistent on Debian/Ubuntu, iptables.service on RHEL).

๐Ÿ“ Tables, Chains, and Packet Flow

iptables organizes rules into tables (by function) and chains (by packet lifecycle stage). Understanding this is the key to everything else.

INPUT

Packets destined for this host. Controls what arrives at local processes.

OUTPUT

Packets originating from this host. Controls outbound traffic.

FORWARD

Packets passing through this host (routing/NAT gateways).

PREROUTING

Before routing decision. Used for DNAT โ€” redirecting incoming packets.

POSTROUTING

After routing decision. Used for SNAT/MASQUERADE โ€” outbound NAT.

Targets

ACCEPT ยท DROP ยท REJECT ยท LOG ยท DNAT ยท SNAT

Network Packet In โ†“ PREROUTING (nat) โ†“ Routing Decision โ†™ โ†˜ INPUT (filter) FORWARD (filter) โ†“ โ†“ Local Process POSTROUTING (nat) โ†“ โ†“ OUTPUT (filter) Packet Out โ†˜ โ†™ POSTROUTING (nat) โ†“ Packet Out

๐Ÿ“‹ Examples

Example 1: View Current Rules

Always start by seeing what is already in place:

# List all rules in the filter table (default)
sudo iptables -L

# List with line numbers and numeric addresses (faster, no DNS)
sudo iptables -L -n --line-numbers

# List with verbose output (shows packet/byte counts)
sudo iptables -L -v -n

# List a specific chain
sudo iptables -L INPUT -n --line-numbers

# List the NAT table
sudo iptables -t nat -L -n

Typical output:

Chain INPUT (policy ACCEPT)
num  target     prot opt source          destination
1    ACCEPT     all  --  0.0.0.0/0       0.0.0.0/0    state RELATED,ESTABLISHED
2    ACCEPT     tcp  --  0.0.0.0/0       0.0.0.0/0    tcp dpt:22
3    DROP       all  --  0.0.0.0/0       0.0.0.0/0
๐Ÿ’ก Always use -n: Without -n, iptables does reverse DNS on every address which can be extremely slow when you have hundreds of rules.
Example 2: Allow Incoming SSH (Port 22)

The most essential rule โ€” allowing your own access before locking anything down:

# Allow incoming SSH from anywhere
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# Better โ€” allow SSH only from a specific management network
sudo iptables -A INPUT -p tcp -s 192.168.1.0/24 --dport 22 -j ACCEPT

# Allow established/related connections back in (stateful โ€” essential)
sudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
โš ๏ธ Do this FIRST: If you are managing a remote server, always add your SSH ACCEPT rule before adding any DROP or restrictive policy. Lock yourself out and you are looking at console access or a rescue boot.

Flags explained:

Example 3: Allow Web Traffic (HTTP and HTTPS)
# Allow HTTP
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT

# Allow HTTPS
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# Both in one rule using multiport
sudo iptables -A INPUT -p tcp -m multiport --dports 80,443 -j ACCEPT

# Allow outbound HTTP/HTTPS from this server (for yum/apt updates)
sudo iptables -A OUTPUT -p tcp -m multiport --dports 80,443 -j ACCEPT
๐Ÿ’ก multiport module: The -m multiport match extension lets you specify up to 15 ports in a single rule, which is far more efficient than writing one rule per port.
Example 4: Block a Specific IP Address
# Drop all traffic from a specific IP (silently)
sudo iptables -A INPUT -s 203.0.113.42 -j DROP

# Reject with ICMP error (tells sender they are blocked)
sudo iptables -A INPUT -s 203.0.113.42 -j REJECT

# Block a /24 subnet
sudo iptables -A INPUT -s 203.0.113.0/24 -j DROP

# INSERT at position 1 (before other rules) for immediate effect
sudo iptables -I INPUT 1 -s 203.0.113.42 -j DROP
DROP vs REJECT: DROP silently discards โ€” the sender gets no response and must wait for a timeout. REJECT sends an ICMP "port unreachable" back immediately. DROP is better for blocking attackers (wastes their time); REJECT is friendlier for legitimate but misconfigured clients.
Example 5: Allow Loopback and ICMP (Ping)

Two rules that should be in almost every ruleset:

# Always allow loopback interface โ€” many services depend on 127.0.0.1
sudo iptables -A INPUT -i lo -j ACCEPT
sudo iptables -A OUTPUT -o lo -j ACCEPT

# Allow ICMP (ping) โ€” useful for diagnostics
sudo iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT

# Or allow all ICMP types
sudo iptables -A INPUT -p icmp -j ACCEPT
โš ๏ธ Never block loopback: Dropping traffic on lo breaks local services that communicate via 127.0.0.1 โ€” databases, caching layers, local APIs. Always explicitly ACCEPT loopback before setting a DROP default policy.
Example 6: Set Default Policy (DROP Everything Else)

After adding all your ACCEPT rules, set a default DROP policy to block everything not explicitly allowed:

# Set default policy to DROP for INPUT and FORWARD
sudo iptables -P INPUT DROP
sudo iptables -P FORWARD DROP

# Usually leave OUTPUT as ACCEPT (or restrict as needed)
sudo iptables -P OUTPUT ACCEPT
โš ๏ธ Order matters critically: Set your ACCEPT rules before setting the default policy to DROP โ€” or you will lock yourself out immediately. The safe sequence is:
1. ACCEPT loopback
2. ACCEPT ESTABLISHED,RELATED
3. ACCEPT your management ports (SSH)
4. ACCEPT your service ports (80, 443, etc.)
5. Then set -P INPUT DROP
Example 7: Delete and Insert Rules
# View rules with line numbers first
sudo iptables -L INPUT -n --line-numbers

# Delete rule by line number (deletes rule #3 from INPUT)
sudo iptables -D INPUT 3

# Delete by matching the exact rule specification
sudo iptables -D INPUT -p tcp --dport 8080 -j ACCEPT

# Insert a rule at a specific position (position 2)
sudo iptables -I INPUT 2 -p tcp --dport 8443 -j ACCEPT

# Replace rule at position 3
sudo iptables -R INPUT 3 -p tcp -s 10.0.0.0/8 --dport 22 -j ACCEPT
๐Ÿ’ก -A vs -I: -A (append) adds to the end of the chain. -I (insert) adds at a position โ€” default position 1 means top of chain. Rules are evaluated top-to-bottom; first match wins.
Example 8: Logging Dropped Packets

LOG target writes to syslog without stopping packet processing โ€” use it before DROP:

# Log and then drop โ€” two rules, same match
sudo iptables -A INPUT -p tcp --dport 23 -j LOG --log-prefix "TELNET ATTEMPT: " --log-level 4
sudo iptables -A INPUT -p tcp --dport 23 -j DROP

# Log all dropped packets (place just before your final DROP rule)
sudo iptables -A INPUT -j LOG --log-prefix "IPT DROP: " --log-level warning

# View the log
sudo journalctl -k | grep "IPT DROP"
sudo grep "IPT DROP" /var/log/kern.log
LOG is non-terminating: Unlike ACCEPT or DROP, LOG does not stop processing. The packet continues to the next rule after being logged. Always follow a LOG rule with DROP/REJECT if you want to block the packet.
Example 9: NAT โ€” Masquerade for Internet Sharing

Turn a Linux box into a NAT gateway (e.g., sharing a single public IP):

# Enable IP forwarding (also set in /etc/sysctl.conf for persistence)
echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward

# MASQUERADE outbound traffic on the public interface (eth0)
sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

# Allow forwarding between interfaces
sudo iptables -A FORWARD -i eth1 -o eth0 -j ACCEPT
sudo iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT

Port forwarding (DNAT) โ€” redirect incoming port to an internal host:

# Forward port 8080 on public IP to internal web server port 80
sudo iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 192.168.1.10:80

# Allow the forwarded traffic through
sudo iptables -A FORWARD -p tcp -d 192.168.1.10 --dport 80 -j ACCEPT
๐Ÿ’ก MASQUERADE vs SNAT: Use MASQUERADE when your public IP is dynamic (DHCP). Use SNAT --to-source x.x.x.x when your public IP is static โ€” it is slightly faster since the kernel does not need to look up the interface IP each time.
Example 10: Rate Limiting โ€” Brute Force Protection

Limit connection attempts to SSH to slow brute-force attacks:

# Allow SSH but limit to 4 new connections per minute per source IP
sudo iptables -A INPUT -p tcp --dport 22 -m state --state NEW \
    -m recent --set --name SSH_CHECK

sudo iptables -A INPUT -p tcp --dport 22 -m state --state NEW \
    -m recent --update --seconds 60 --hitcount 4 --name SSH_CHECK -j DROP

# Simpler limit using the limit module
sudo iptables -A INPUT -p tcp --dport 22 -m limit --limit 3/min \
    --limit-burst 5 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 22 -j DROP
fail2ban: For production brute-force protection, consider fail2ban โ€” it dynamically adds iptables rules based on log analysis and automatically expires them. More flexible than static rate limits.
Example 11: Save and Restore Rules

Rules are lost on reboot unless explicitly saved:

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

# Restore rules from file
sudo iptables-restore < /etc/iptables/rules.v4

# Debian/Ubuntu โ€” install persistence package
sudo apt install iptables-persistent
sudo netfilter-persistent save

# RHEL/CentOS โ€” save via service
sudo service iptables save
# or
sudo /sbin/iptables-save > /etc/sysconfig/iptables

# Flush ALL rules (nuclear option โ€” resets to empty)
sudo iptables -F        # flush rules
sudo iptables -X        # delete user-defined chains
sudo iptables -Z        # zero packet/byte counters
sudo iptables -t nat -F # flush NAT table
โš ๏ธ Flush resets policy too? No โ€” -F flushes rules but does NOT reset the default policy. If your policy is DROP and you flush all rules, you will still have a DROP policy with no ACCEPT rules โ€” effectively locking out all traffic. Reset the policy first: sudo iptables -P INPUT ACCEPT

โš™๏ธ Command Flag Reference

FlagMeaningExample
-A CHAINAppend rule to chain-A INPUT
-I CHAIN [n]Insert at position n (default: 1)-I INPUT 2
-D CHAIN nDelete rule at line number-D INPUT 3
-R CHAIN nReplace rule at line number-R INPUT 2 ...
-L [CHAIN]List rules-L INPUT -n
-F [CHAIN]Flush (delete all rules)-F INPUT
-P CHAIN TARGETSet default policy-P INPUT DROP
-t TABLESpecify table (default: filter)-t nat
-p PROTOProtocol: tcp, udp, icmp, all-p tcp
-s ADDRSource address/network-s 10.0.0.0/8
-d ADDRDestination address/network-d 192.168.1.5
--dport PORTDestination port--dport 443
--sport PORTSource port--sport 1024:65535
-i IFACEInbound interface-i eth0
-o IFACEOutbound interface-o eth0
-j TARGETJump to target-j ACCEPT
-nNumeric โ€” no DNS resolution-L -n
-vVerbose โ€” show counters-L -v
--line-numbersShow rule line numbers-L --line-numbers

๐Ÿš€ Quick Reference Card

TaskCommand
View all rules (numbered)sudo iptables -L -n --line-numbers
View with packet countssudo iptables -L -v -n
Allow SSH from anywheresudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT
Allow SSH from subnetsudo iptables -A INPUT -p tcp -s 10.0.0.0/8 --dport 22 -j ACCEPT
Allow established sessionssudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
Allow loopbacksudo iptables -A INPUT -i lo -j ACCEPT
Allow HTTP + HTTPSsudo iptables -A INPUT -p tcp -m multiport --dports 80,443 -j ACCEPT
Block an IPsudo iptables -I INPUT 1 -s 203.0.113.42 -j DROP
Set DROP default policysudo iptables -P INPUT DROP
Delete rule by line numbersudo iptables -D INPUT 3
Flush all rulessudo iptables -F
Save rules (Debian/Ubuntu)sudo netfilter-persistent save
Save rules (RHEL/CentOS)sudo service iptables save
Save to file (any distro)sudo iptables-save > /etc/iptables/rules.v4
Restore from filesudo iptables-restore < /etc/iptables/rules.v4
๐Ÿ”„ Modern Alternatives: iptables is being replaced by nftables (kernel 3.13+), with firewalld as a management layer on RHEL/CentOS/Fedora and ufw on Ubuntu/Debian. On RHEL 8+ and Ubuntu 20.04+, iptables commands are often translated to nftables rules transparently via iptables-nft. The concepts โ€” chains, targets, stateful matching โ€” carry directly over. Learn iptables; everything else is a dialect.