The iptables firewall is a popular firewall package for many GNU/Linux distributions. It is one of the many software packages maintained by Linux kernel developers at You should consider using iptables, either directly or through a simplified front-end (such as ufw), to further secure your devices and your network.


As a generalized packet filter, iptables can be used for a number of purposes and in a number of configurations, like any decent firewall. These include:

and more. Our recommendation is to use some firewall (not necessarily iptables, but an equivalent) to fulfill all of the above roles. Which specific role a given instance of iptables will take on largely depends on its logical position in your network topology. For example, an installation of iptables on your local workstation cannot, by definition, serve as a network-wide traffic redirector.

Depending on your use case, iptables can secure your system(s) by performing all or some of the following functions:

The iptables(8) utility is a userland program that an administrator uses to manipulate a list of filtering rules stored in kernel memory. (ip6tables(8) offers the same capabilities for IPv6 packets.) These rules are applied by the Linux kernel itself against all incoming and outgoing IP network packets; this means there is no daemon to start or stop, changes take effect immediately, and changes are lost across reboots unless the configuration is saved and reloaded during system boot by networking scripts (or the iptables-persistent plugin, possibly available as a package from your distro’s package repositories). The conceptual model for interacting with iptables is as follows:

  1. A given rule describes what an IP network packet might look like along with an associated action (a “target”) to take when a processed packet matches the description given in the rule.
  2. The rules are sorted in a list, called a chain.
  3. These chains (lists of rules) are themselves contained within a number of pre-defined or user-defined tables, hence the tool’s name, iptables.

Configuring iptables correctly is the process of editing or removing existing rules, chains, or tables in such a way as to describe the ruleset for permitted or forbidden ingress or egress packets that touch the system on which iptables is run, and what actions to take (i.e., “which target chains to jump to”) in what order while processing the packet. Basic firewall configuration merely requires editing the filter tables’s rules; this is the default table (if no -t or --table option is specified), so you may not even need to concern yourself with tables at all.


The iptables (userland utility) and iptables-persistent (boot-time scripts) package is typically availble from your operating system distribution’s package repositories. On a Debian-based GNU/Linux distribution, install it by invoking:

sudo apt update && sudo apt install iptables iptables-persistent


This section describes various configurations we have found useful.

Configuring iptables as a single-host defensive measure

Do this to configure iptables as a single-host defensive measure:

  1. Append a rule allowing any traffic from the loopback interface (-i lo):
    sudo iptables -A INPUT -i lo -j ACCEPT
  2. Allow traffic that is part of an already-established connection:
    sudo iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
  3. If you use SSH, allow TCP traffic to ingress via the default ssh port (typically 22, but change this to match your system’s configuration, of course):
    sudo iptables -A INPUT -p tcp --dport ssh -j ACCEPT
    # Optionally, restrict inbound SSH traffic to a specific machine (a Secure Admin Workstation [SAW] or "jumpbox")
    #sudo iptables -A INPUT -p TCP -s --dport ssh -j ACCEPT
  4. Allow traffic to ingress via any other required ports for your configuration, for example a Web server, or an mDNS responder:
    sudo iptables -A INPUT -p tcp --dport http -j ACCEPT # Web traffic.
    sudo iptables -A INPUT -p udp --dport mdns -j ACCEPT # mDNS traffic.
  5. Finally, silently deny all other inbound IPv4 traffic by changing the INPUT chain’s default target (its “policy”) to DROP.
    sudo iptables --policy INPUT DROP
  6. Persist changes to your IPv4 filtering rules across reboots:
    sudo iptables-save | sudo tee /etc/iptables/rules.v4
  7. Repeat the above procedure for IPv6, performed almost identically except for the use of the ip6tables(8) utility in place of iptables(8) and the addition of a firewall rule allowing ICMPv6 Neighbor Solicitation messages (see RFC 4890 ยง A.6). For instance:
    sudo ip6tables -A INPUT -i lo -j ACCEPT                                      # Allow any IPv6 traffic from the loopback interface.
    sudo ip6tables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT # Accept any already-established IPv6 traffic.
    sudo ip6tables -A INPUT -p icmpv6 --icmpv6-type neighbor-solicitation -j ACCEPT # Required to establish link-local IPv6 conversations.
    sudo ip6tables -A INPUT -p tcp --dport ssh -j ACCEPT                         # Accept SSH connections carried by IPv6.
    # Optionally, restrict inbound SSH traffic to a specific machine (a Secure Admin Workstation [SAW] or "jumpbox")
    #sudo ip6tables -A INPUT -p tcp -s 1234:5678:9abc:42::100 --dport ssh -j ACCEPT
    # Additional rules here, if you have need for any.
  8. Finally, silently deny all other inbound IPv6 traffic by changing the INPUT chain’s default target (its “policy”) to DROP.
    sudo ip6tables --policy INPUT DROP
  9. Persist changes to your IPv6 filtering rules across reboots:
    sudo ip6tables-save | sudo tee /etc/iptables/rules.v6

Configuring iptables as a network perimeter defensive measure


Configure egress restrictions

Outbound traffic (“egress netflows”) can be shaped just as inbound traffic (“ingress netflows”) can. Whereas filtering ingress network packets protects the system from network-borne attacks attempting to penetrate the system, filtering egress network packets can help to frustrate a successful attacker’s attempts to exfiltrate data from the network. Egress restrictions can be implemented as a single-host defensive measure, but will usually be less effective when implemented in that configuration since, if an attacker has already compromised the system, they may be more easily able to make changes to the host’s firewall configuration as well. For this reason, outbound filtering rules are usually implemented on a device at the network perimeter or in the gateway machine itself.

Do this to configure egress restrictions:




Log before dropping

# Make a new user-defined target (a chain).
sudo iptables -N LOGGING
# Append the "LOGGING" jump target at the end of the INPUT chain.
sudo iptables -A INPUT -j LOGGING
# Create a rule whose action is to add a log line.
# See `man iptables-extensions` for additional options.
# Use the `limit` module (`-m limit`), log only 2 matched packets per min (`--limit 2/min`)
sudo iptables -A LOGGING -m limit --limit 2/min -j LOG --log-prefix "IPTables Packet Dropped: " --log-level 7

or, e.g.,

# Just add the `LOG` extended target via the `limit` module directly to the end of the INPUT chain.
sudo iptables -A INPUT -m limit --limit 2/min -j LOG --log-prefix "IPTables Packet Dropped: " --log-level 7
# If your INPUT chain policy is not DROP already, either set it to be:
#sudo iptables -P INPUT DROP
# or add an explicit DROP target:
sudo iptables -A INPUT -j DROP


Your iptables packet filter chains can be automatically hardened by security software such as Fail2ban.


The AnarchoTech NYC collective provides an Ansible role for installing and configuring iptables rules that runs on a Raspberry Pi. It can be installed in your local $ANSIBLE_ROLES_PATH (see Ansible Configuration Settings) for use with an Ansible project with:

ansible-galaxy install

See also