Skip to content

/flags/iptables/iptables-i-insert-vs-a-append

iptables -I vs -A: insert a rule at the top instead of appending it

The commands on this page have not been executed by our verification runner yet.updated
tool
iptables / nftables
command
iptables
flag
-I, --insert CHAIN [RULENUM]
default
-I without a number inserts at position 1 (the head of the chain); -A always adds at the end

iptables -I INPUT -s 192.0.2.10 -j DROP inserts the rule at the top of the INPUT chain, while iptables -A INPUT ... appends it at the end. The difference matters because netfilter evaluates the rules of a chain in order and stops at the first terminating target (ACCEPT, DROP, REJECT). A blocking rule appended after an existing ACCEPT for the same traffic never runs; inserted before it, it takes effect immediately. -I CHAIN N inserts at position N, shifting the existing rule N and everything after it down by one.

Commands

bash
sudo iptables -L INPUT -n --line-numbers          # current order with positions
sudo iptables -I INPUT -s 192.0.2.10 -j DROP      # becomes rule 1
sudo iptables -I INPUT 3 -p tcp --dport 8080 -j ACCEPT   # becomes rule 3
sudo iptables -A INPUT -j LOG --log-prefix "INPUT-END: " # added after the last rule

Rule-position options

OptionPositionTypical use
-A, --append CHAINEnd of the chainBuilding a rule set in order from a script
-I, --insert CHAINPosition 1Emergency block of an address, ahead of all ACCEPT rules
-I CHAIN NPosition NPlacing a rule between existing ones
-R, --replace CHAIN NReplaces rule NChanging a rule in place without reordering
-D, --delete CHAIN N or specRemoves a ruleUndoing a rule by number or by full specification
-C, --check CHAIN specNoneTest whether a rule exists before adding it (idempotent scripts)

Order pitfalls

  • Default policy versus final rule. A chain policy (-P INPUT DROP) applies only after all rules; an explicit -A INPUT -j REJECT at the end behaves similarly but is a real rule, so later -A rules land after it and never match. Use -I or insert before it.
  • Established traffic first. Rule sets usually begin with an ESTABLISHED,RELATED accept (see conntrack --ctstate). Inserting a broad DROP at position 1 puts it above that rule and can cut existing sessions, including your SSH connection.
  • Scripts that run twice. -A in a script that is re-run duplicates rules; check with -C first or flush and rebuild. Deleting a specification that does not exist fails with Bad rule (does a matching rule exist in that chain?).
  • Positions change. After an insert or delete, numbers shift; list again with --line-numbers before using a position, as shown in list rules with line numbers.
  • Front ends manage order themselves. ufw, firewalld and Docker insert their own chains; adding rules directly to INPUT or FORWARD with -A may place them after a jump that already decides. Docker documents the DOCKER-USER chain for custom rules.

Blocking a single address end to end is covered in block an IP address, and removing rules in delete a rule.

FAQ

Why does my new iptables rule have no effect?

It was probably appended with -A after a rule that already matches the packet, such as a REJECT-all or an ACCEPT for the same traffic. The first matching terminating rule wins, so insert the rule earlier with -I CHAIN N.

What does iptables -I INPUT without a number do?

It inserts the rule at position 1, the head of the chain. The manual states that 1 is the default when no rule number is given.

How do I see the rule numbers?

iptables -L INPUT -n --line-numbers prints the position of every rule, which is the number -I, -R and -D expect.

Sources