iptables Command in Linux: Manage Firewall Rules

By 

Updated on

9 min read

Using iptables to manage firewall rules in Linux

When a packet arrives at a Linux machine, the kernel decides what to do with it based on a set of firewall rules. Those rules live in the kernel’s Netfilter framework, and for more than two decades the standard way to edit them from user space has been the iptables command.

iptables controls packet filtering, network address translation, and packet mangling. Higher-level front ends such as ufw and firewalld manage the same Netfilter firewall stack through simpler interfaces, although many modern systems use nftables underneath. Understanding the underlying command is still valuable, especially when you inherit a server that was set up by someone else. This guide walks through the concepts and the commands you need to read, edit, and persist firewall rules.

Tables and Chains

Before you write a rule, you need to know where it goes. iptables is organized into tables, and each table contains chains.

The three tables you will use most often are:

  • filter - the default table, used for allowing and blocking traffic
  • nat - used for network address translation, such as port forwarding and masquerading
  • mangle - used to alter packet headers, for example to set QoS marks

Each table has a set of built-in chains that correspond to moments in the life of a packet. In the filter table:

  • INPUT - packets destined for the local machine
  • OUTPUT - packets originating from the local machine
  • FORWARD - packets routed through the machine

A rule says: for packets that enter this chain and match these criteria, take this action. The action is called a target and is usually ACCEPT, DROP, REJECT, or the name of another chain.

iptables Syntax

The general form of the command is:

txt
iptables [-t TABLE] COMMAND CHAIN [MATCH] [-j TARGET]

If -t is omitted, iptables uses the filter table. Common commands include -A (append a rule), -I (insert), -D (delete), -L (list), -F (flush), and -P (set default policy).

All commands that change the firewall require root privileges. Run them with sudo or as root.

Warning
It is easy to lock yourself out of a remote server with a single wrong rule. Before you apply a restrictive ruleset over SSH, either test on a local machine first or use iptables-apply, which rolls back automatically if you lose access.

List Rules

To print every rule in the filter table, use the -L option:

Terminal
sudo iptables -L

The default output shows service names, resolves IP addresses, and hides packet and byte counters. For real work, add -n to keep numeric output and -v to show counters and interface information:

Terminal
sudo iptables -L -n -v
output
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
 1234 98K   ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0   tcp dpt:22
    0    0 DROP       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0   tcp dpt:23

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination

To list a single chain, append its name:

Terminal
sudo iptables -L INPUT -n -v

To number the rules so you can reference them by index when deleting, add --line-numbers:

Terminal
sudo iptables -L INPUT -n -v --line-numbers

Add and Remove Rules

New rules are added to the end of a chain with -A (append) or at a specific position with -I (insert). The difference matters because iptables evaluates rules top to bottom and stops at the first match.

To allow incoming SSH connections:

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

To allow HTTP and HTTPS:

Terminal
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT

To insert a rule as the first one in the chain, use -I CHAIN 1:

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

This is important when you are working over SSH. If a broad DROP rule already appears earlier in the chain, appending the accept rule after it would not help because the packet would be dropped first.

To delete a rule, either repeat the exact specification with -D:

Terminal
sudo iptables -D INPUT -p tcp --dport 23 -j DROP

Or delete by line number, which is easier when the rule has many options:

Terminal
sudo iptables -D INPUT 3

Allow and Block Specific IPs

To block all traffic from a single IP address:

Terminal
sudo iptables -A INPUT -s 203.0.113.10 -j DROP

To block a range using CIDR notation:

Terminal
sudo iptables -A INPUT -s 203.0.113.0/24 -j DROP

To allow SSH only from a trusted subnet:

Terminal
sudo iptables -A INPUT -p tcp -s 192.168.1.0/24 --dport 22 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 22 -j DROP

The first rule accepts SSH from the local subnet. The second drops SSH from everywhere else. Order matters: if you reversed the two lines, every SSH attempt would be dropped before the accept rule had a chance to match.

Allow Established Connections

Most firewall setups include a rule that accepts traffic belonging to an already established connection. This lets return traffic through without needing a matching rule for each outbound request:

Terminal
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

Put this rule near the top of the INPUT chain so it matches early. Without it, the default DROP policy breaks outbound connections that expect responses.

Set a Default Policy

Each built-in chain has a default policy that applies when no rule matches. The -P option changes it:

Terminal
sudo iptables -P INPUT DROP
sudo iptables -P FORWARD DROP
sudo iptables -P OUTPUT ACCEPT

Switching INPUT to DROP is the foundation of a deny-by-default firewall: nothing gets in unless an explicit rule allows it. Before you flip the policy, make sure you have already added the rules that allow SSH, established connections, and anything else you need.

Flush Rules

To remove every rule from every chain in the current table:

Terminal
sudo iptables -F

To flush a specific chain only:

Terminal
sudo iptables -F INPUT

Flushing does not reset the default policies. If you have set INPUT to DROP, flushing will leave it at DROP with no rules, which blocks all inbound traffic. Reset the policy to ACCEPT first if that is not what you want:

Terminal
sudo iptables -P INPUT ACCEPT
sudo iptables -F

Save and Restore Rules

Rules added with iptables live in kernel memory only. They disappear on reboot unless you save them.

On Ubuntu, Debian, and Derivatives, the iptables-persistent package saves rules to /etc/iptables/rules.v4 and reloads them at boot:

Terminal
sudo apt install iptables-persistent

The installer asks whether to save the current rules. To update the saved copy later:

Terminal
sudo netfilter-persistent save

On Fedora, RHEL, and Derivatives, the equivalent service is iptables-services:

Terminal
sudo dnf install iptables-services
sudo systemctl enable --now iptables
sudo service iptables save

Independent of the distribution, you can dump and restore rules manually with iptables-save and iptables-restore:

Terminal
sudo iptables-save -f /etc/iptables/rules.v4
sudo iptables-restore /etc/iptables/rules.v4

This is also the recommended way to edit a large ruleset: save to a file, edit the file, then restore it atomically.

Troubleshooting

Rules disappear after a reboot
iptables rules are not persistent by default. Install iptables-persistent on Debian-based systems or iptables-services on RHEL-based ones, and save the ruleset.

SSH stops working after setting a DROP policy
You switched INPUT to DROP without an ACCEPT rule for port 22, or the ACCEPT rule is positioned after a more general DROP rule. Connect through the console, add the rule with -I INPUT 1, and save.

A rule looks correct but does not match
Check the order. iptables walks the chain top to bottom and stops at the first match, so an earlier accept or drop may be catching the packet first. Use iptables -L INPUT -n -v --line-numbers to inspect the order.

Changes are silently ignored
You may be editing the wrong table. A rule in filter does not affect NAT, and vice versa. Pass -t TABLE explicitly when you are not working in filter.

iptables: command not found
On some modern distributions, only nftables is installed by default. Install iptables with your package manager, or use nft directly.

Quick Reference

For a printable quick reference, see the iptables cheatsheet .

ActionCommand
List rules (verbose, numeric)iptables -L -n -v --line-numbers
Allow portiptables -A INPUT -p tcp --dport PORT -j ACCEPT
Block IPiptables -A INPUT -s IP -j DROP
Allow established connectionsiptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
Insert rule at topiptables -I INPUT 1 -p tcp --dport 22 -j ACCEPT
Delete rule by numberiptables -D INPUT N
Set default policyiptables -P INPUT DROP
Flush all rulesiptables -F
Save rulesiptables-save -f /etc/iptables/rules.v4
Restore rulesiptables-restore /etc/iptables/rules.v4

FAQ

Is iptables still relevant in 2026?
It is still installed and widely used, but it is being replaced by nftables, which offers a cleaner syntax and better performance. On recent distributions, the iptables command is often a compatibility front end that writes nftables rules underneath.

Should I use iptables, ufw, or firewalld?
If you are managing rules by hand on Debian or Ubuntu, ufw is simpler and covers most cases. On Fedora and RHEL, firewalld is the default. Reach for raw iptables when you need fine-grained control that the front ends do not expose, or when you are troubleshooting an existing ruleset.

What is the difference between DROP and REJECT?
DROP silently discards the packet; the sender sees a timeout. REJECT sends an ICMP error back (or a TCP reset for TCP), so the sender gets immediate feedback. DROP is often preferred on public interfaces because it does not confirm that the port exists.

How do I block a country or a list of IPs?
For a handful of addresses, add one -s rule per entry. For larger lists, use the ipset tool to manage the addresses and reference the set from a single iptables rule.

Does iptables handle IPv6?
No. Use ip6tables for IPv6 rules. It has the same syntax and the same tables and chains, but operates on a separate rule set.

Conclusion

iptables is a low-level but reliable way to read and shape the Linux firewall. Once you have a working ruleset, save it with iptables-save and commit the file so the next person to touch the server has a clear starting point.

Linuxize Weekly Newsletter

A quick weekly roundup of new tutorials, news, and tips.

About the authors

Dejan Panovski

Dejan Panovski

Dejan Panovski is the founder of Linuxize, an RHCSA-certified Linux system administrator and DevOps engineer based in Skopje, Macedonia. Author of 800+ Linux tutorials with 20+ years of experience turning complex Linux tasks into clear, reliable guides.

View author page