The Linux kernel has a great firewall built-in commonly referred to as iptables. Actually iptables is only the user-space tool that you as the user interact with, while the kernel module doing all the work is actually called Netfilter.

Here are a few tips on how to quickly set up a filtering firewall on a Linux box.

The filtering mechanism uses a series of groups called “chains” in the literature. The main predefined chains are:

  • INPUT — All the packets reaching the host computer
  • OUTPUT — Packets originating from the host computer
  • FORWARD — Packets routed / passing through.

Each of these chains can have a default policy such as accepting all packets by default or dropping them.

Individual rules are then added to a List-like structure within each of these chains. Rules are then read from the top to the bottom for each intercepted IP packet.

Let’s go on and add a few rules. These commands are all run as the superuser.

iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -p tcp -m multiport --dports 80,443 -j ACCEPT

The iptables command can append (-A), insert (-I), delete (-D) rules from the list. In this case we append to the INPUT chain.

The first one will allow all requests to the lo interface: a shorthand for the localhost.
The -j flag indicates which action should be applied when the rule is matched, such as ACCEPT, DROP, etc.

The second rule will allow all inbound TCP packets on ports 80 and 443. IPTables uses the concept of extensions. These are loaded using the -m flag.
For the second rule we use the multiport extension which allows to specify two ports at once.

You probably also want to allow UDP traffic on the same ports to account for newer protocols such as QUIC.

We don’t necessarily have to use extensions, a simple rule will also work such as this one, where all inbound traffic on TCP port 22 is accepted.

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

However a cautious user will move their SSH daemon from port 22 to something a bit more obscure, and turn on public key based authentication.

All rules can then be visualised using a command such as:

iptables -nL --line-numbers

This will display each rule preceded by its line number. This is significant as we’ll see in the following example.

Due to how some protocols work we will also have to allow inbound traffic in reply to outbound traffic that was initiated from the host machine.

iptables -I INPUT 2 -m state --state ESTABLISHED -j ACCEPT

We want this rule to be inserted near the top of the INPUT chain on the 2nd position in the list, because it will be used quite a lot. We then use the state extension here, which enables us to specify that for already established connections the firewall should allow all inbound traffic. This rule is important as without it many protocols will break (such as outbound HTTP from the host machine).

If we now list the chain rules again we can see that this was added to the 2nd position:

Chain INPUT (policy ACCEPT)
num  target     prot opt source        destination
1    ACCEPT     all  --  0.0.0.0/0     0.0.0.0/0 
2    ACCEPT     all  --  0.0.0.0/0     0.0.0.0/0     state ESTABLISHED
3    ACCEPT     tcp  --  0.0.0.0/0     0.0.0.0/0     multiport dports 80,443
4    ACCEPT     udp  --  0.0.0.0/0     0.0.0.0/0     multiport dports 80,443
5    ACCEPT     tcp  --  0.0.0.0/0     0.0.0.0/0     tcp dpt:22
...

Don’t worry if you make a mistake, rules can always be deleted by their index in the chain.

iptables -D INPUT 6

Or even flush the entire chain with:

iptables -F INPUT

Finally we could drop all the remaining traffic with something like:

iptables -A INPUT -j DROP

But then the drop rule will always have to stay at the bottom of the chain. A better practice is to change the Policy of the entire chain to DROP:

iptables -P INPUT DROP

This will then be the default catch-all action for each packet which doesn’t match one of the rules we defined.

Chain INPUT (policy DROP)
...

As for the OUTPUT chain, this usually has a default ACCEPT policy, as we generally trust all outbound traffic from our machine.

iptables -P OUTPUT ACCEPT

Finally persist the state of the chains to the disk, and make sure that the iptables service is enabled by your daemon manager — such as systemd.

iptables-save > /etc/iptables/iptables.rules
systemctl enable iptables

This will ensure that the rules are actually kept and loaded between reboots. And we are done, you have now configured a few simple filtering rules for your Linux firewall. Below are a few good resources to further your knowledge with iptables.

Read More