Where to start First steps track · 15 stages
Linux Labs

The classic iptables firewall

5 min Linux · iptables

The classic Linux firewall — chains, rules, NAT, and why nftables replaced it.

Cheat sheet

7 commands Printable version
  • sudo iptables -L -n -v --line-numbers read the rules
  • sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT SSH first!
  • sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
  • sudo iptables -I INPUT 1 -s 10.0.0.5 -j DROP ban an IP as the first rule
  • sudo iptables -P INPUT DROP default policy — deny
  • sudo iptables -D INPUT 3 delete rule number 3
  • sudo netfilter-persistent save persist to disk

Overview

iptables is the classic interface to the Linux firewall. On modern systems it has been replaced by nftables (on Ubuntu, iptables usually translates into nftables), but iptables rules and syntax are still everywhere — you need to be able to read and edit them.

The model: tables (filter, nat, mangle) → chains (INPUT, FORWARD, OUTPUT, PREROUTING, POSTROUTING) → rules in order → an action (ACCEPT/DROP/REJECT).

Options

10
Option Meaning
-L list rules (-n skips DNS, -v adds counters)
-t TABLE table: filter (default), nat, mangle
-A CHAIN append a rule to the end of the chain
-I CHAIN [N] insert at the start / at position N
-D CHAIN N delete rule N
-P CHAIN ACT the chain's default policy
-F flush the chain
-p / --dport / -s / -i protocol / destination port / source / interface
-j action: ACCEPT, DROP, REJECT, DNAT, SNAT, MASQUERADE
--line-numbers rule numbers (for -D/-I)

Nothing found. Try a shorter query.

Recipes

1

Reading and rules

bash
sudo iptables -L -n -v                       # filter rules, no DNS, with counters
sudo iptables -L INPUT -n --line-numbers     # INPUT with numbers (for delete/insert)
sudo iptables -t nat -L -n -v                # the NAT table

# a basic INPUT set (order matters!):
sudo iptables -A INPUT -i lo -j ACCEPT                                 # loopback
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT  # replies
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT                     # SSH (FIRST!)
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT                     # HTTP
sudo iptables -P INPUT DROP                                            # policy — drop

# targeted operations:
sudo iptables -I INPUT 1 -s 10.0.0.5 -j DROP    # insert first: ban an IP
sudo iptables -D INPUT 3                          # delete rule #3
sudo iptables -F INPUT                            # flush the INPUT chain

# NAT (forward a port to an internal host):
sudo iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to 10.0.0.10:80
sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE   # gateway/SNAT

iptables rules don't persist on their own. Persistence comes from the iptables-persistent package (sudo netfilter-persistent save), or from moving to nftables.

Troubleshooting

5

Locked yourself out of SSH

The rule for 22/tcp must come before the DROP policy. If you're already locked out — go through the console (KVM/IPMI): sudo iptables -I INPUT 1 -p tcp --dport 22 -j ACCEPT. For remote work it helps to schedule an auto-rollback (at now+5min running a flush).

Rules disappeared after a reboot

iptables isn't persistent. Run sudo netfilter-persistent save (with iptables-persistent installed), or move to nftables/ufw (see firewall).

Order matters

Rules apply top to bottom, stopping at the first match. Check --line-numbers, and insert at the right spot with -I CHAIN N ... rather than only appending with -A.

Counters don't grow — the rule isn't firing

-L -v shows per-rule packet counters. Zero means traffic never reaches this rule (caught earlier) or it's the wrong interface/chain.

Not sure whether it's really iptables or nftables

On Ubuntu, iptables is often iptables-nft (the nftables backend). The real rule set is sudo nft list ruleset (see firewall).

Danger zone

Danger. iptables -F (flush) removes every rule in the current table without confirmation. If the policy is already -P INPUT DROP, flushing the rules doesn't restore ACCEPT — the connection, including your current SSH session, drops immediately. Before running -F on a remote machine, make sure you have console access through the hypervisor, or set -P INPUT ACCEPT beforehand.

Switching the policy to -P INPUT DROP without an allow rule for 22/tcp in place first cuts remote access instantly — the SSH rule goes in before changing the policy, not after.

See also

  • firewall — Traffic filtering — simple ufw and low-level nftables.
  • ss — Who's listening on what ports and which connections are open — the modern netstat.
  • sysctl — Reading and tuning kernel parameters live and persistently (sysctl.conf).
Loading…